tanakh/cmdline

Mysterious segfaults with cmdline with several arguments

susilehtola opened this issue · 1 comments

cmdline appears to have some intrinsic limitation to the number of arguments it can process. I get

$ ./a.out 
Segmentation fault (core dumped)

with the following test program originating from HelFEM

#include "cmdline.h"
#include <vector>
#include <string>

int main(int argc, char **argv) {
  cmdline::parser parser;

  // full option name, no short option, description, argument required
  parser.add<std::string>("Z", 0, "nuclear charge", false, "H");
  parser.add<double>("Rmax", 0, "practical infinity in au", false, 40.0);
  parser.add<int>("grid", 0, "type of grid: 1 for linear, 2 for quadratic, 3 for polynomial, 4 for exponential", false, 4);
  parser.add<double>("zexp", 0, "parameter in radial grid", false, 2.0);
  parser.add<int>("nelem", 0, "number of elements", false, 5);
  parser.add<int>("Q", 0, "charge of system", false, 0);
  parser.add<int>("nnodes", 0, "number of nodes per element", false, 15);
  parser.add<int>("nquad", 0, "number of quadrature points", false, 0);
  parser.add<int>("maxit", 0, "maximum number of iterations", false, 500);
  parser.add<double>("convthr", 0, "convergence threshold", false, 1e-7);
  parser.add<std::string>("method", 0, "method to use", false, "lda_x");
  parser.add<double>("dftthr", 0, "density threshold for dft", false, 1e-12);
  parser.add<int>("restricted", 0, "spin-restricted orbitals", false, -1);
  parser.add<int>("primbas", 0, "primitive radial basis", false, 4);
  parser.add<double>("diiseps", 0, "when to start mixing in diis", false, 1e-2);
  parser.add<double>("diisthr", 0, "when to switch over fully to diis", false, 1e-3);
  parser.add<int>("diisorder", 0, "length of diis history", false, 5);
  parser.parse_check(argc, argv);

  // Get parameters
  double Rmax(parser.get<double>("Rmax"));
  int igrid(parser.get<int>("grid"));
  double zexp(parser.get<double>("zexp"));
  int maxit(parser.get<int>("maxit"));
  double convthr(parser.get<double>("convthr"));
  int restr(parser.get<int>("restricted"));
  int primbas(parser.get<int>("primbas"));
  // Number of elements
  int Nelem(parser.get<int>("nelem"));
  // Number of nodes
  int Nnodes(parser.get<int>("nnodes"));

  // Order of quadrature rule
  int Nquad(parser.get<int>("nquad"));
  double dftthr(parser.get<double>("dftthr"));

  // Nuclear charge
  std::string Z(parser.get<std::string>("Z"));
  int Q(parser.get<int>("Q"));
  double diiseps=parser.get<double>("diiseps");
  double diisthr=parser.get<double>("diisthr");
  int diisorder=parser.get<int>("diisorder");
  std::string method=parser.get<std::string>("method");
  
  std::vector<std::string> rcalc(2);
  rcalc[0]="unrestricted";
  rcalc[1]="restricted";

  printf("Running %s %s calculation with Rmax=%e and %i elements.\n",rcalc[restr].c_str(),method.c_str(),Rmax,Nelem);
  
  return 0;
}

The backtrace doesn't contain any useable information

(gdb) bt
#0  __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:96
#1  0x00007fdb436ba6de in __vfprintf_internal (s=0x7fdb43813780 <_IO_2_1_stdout_>, format=0x4103c8 "Running %s %s calculation with Rmax=%e and %i elements.\n", ap=ap@entry=0x7ffe86b3a540, 
    mode_flags=mode_flags@entry=0) at vfprintf-internal.c:1645
#2  0x00007fdb436a52df in __printf (format=<optimized out>) at printf.c:33
#3  0x0000000000404c48 in main ()

but the code works if you comment out a variable!

If I replace parser.parse_check(argc, argv); with if(!parser.parse(argc, argv)) throw std::logic_error("Parsing error\n"); the program runs without problems(!)

So, the problem must be in the parse_check part of the library.