1

I have a function defined in the header file prog.h, which takes a couple of arguments of the type bool, string and double.

string createDataFolder(bool setPBC, string distribution, double timestep, double simtime, double potRange, double potStrength, 
    double particlesize, bool steric, bool ranRod, bool ranU, bool rand, double dvar, double polydiam, bool Pointq){
    //...
    if (Pointq) folder += "/pointq";
    //....
    return folder;
}

When I call the function from inside my main() function in prog.cpp via

string folder = createDataFolder(setPBC, distribution, timestep, simtime, urange, ustrength, 
     particlesize, includeSteric, ranRod, ranU, rand, dvar, polydiam, Pointq);

the bool parameter Pointq is always passed as false, no matter if it is set to true or false, even if I call the function as

string folder = createDataFolder(setPBC, distribution, timestep, simtime, urange, ustrength, 
     particlesize, includeSteric, ranRod, ranU, rand, dvar, polydiam, true);

If I change the definition of the function definition and call, such that there is another parameter after Pointq, then Pointq is passed correctly, and the last parameter as well.

string createDataFolder(bool setPBC, string distribution, double timestep, double simtime, double potRange, double potStrength, 
    double particlesize, bool steric, bool ranRod, bool ranU, bool rand, double dvar, double polydiam, bool Pointq, bool tmp){
    //...
    if (Pointq) folder += "/pointq";
    //....
    return folder;
}

string folder = createDataFolder(setPBC, distribution, timestep, simtime, urange, ustrength, 
     particlesize, includeSteric, ranRod, ranU, rand, dvar, polydiam, Pointq, true)

If I change the order of the last two arguments of the createDataFolder function, it works as well.

string createDataFolder(bool setPBC, string distribution, double timestep, double simtime, double potRange, double potStrength, 
    double particlesize, bool steric, bool ranRod, bool ranU, bool rand, double dvar, bool Pointq, double polydiam){ ... }

I assume there is a stupid mistake in my code, but I don't know where to look, since I have no intuition, how such an error could occur. I've searched the forum for something similar in C++ but I was not able to find anything.

It would be great if somebody could provide me with some insights or point me to a relevant thread.


EDIT

Here's a minimal example that still produces the error on my machine

#include <iostream>


using namespace std;

void createDataFolder( double potRange, bool Pointq){
    char range[5];
    sprintf(range, "%.3f", potRange);
    cout << "in createDataFolder Pointq is " << Pointq << endl;
}

int main(int argc, const char* argv[]){    
    bool Pointq = true;
    double urange = 10;

    cout << "In main(), Pointq is " << Pointq << endl;
    createDataFolder( urange, Pointq);
    return 0;
}
Johann
  • 572
  • 6
  • 22
  • How are you debugging this? – Mr Lister Nov 02 '16 at 13:22
  • try to shrink your example down to the minimum that it still can be reproducable. You will likely catch your error during this process. – Hayt Nov 02 '16 at 13:22
  • Narrow your problem down to a [MCVE]. You don't need 90,000 function parameters to test and demonstrate the behaviour of just one. – Lightness Races in Orbit Nov 02 '16 at 13:22
  • 4
    Possibly unrelated to your problem, but having a function with that many arguments is usually considered bad style. It makes it very hard to read and understand, and therefore also hard to maintain. – Some programmer dude Nov 02 '16 at 13:23
  • If you remove all the code you've commented out here, leaving only the conditional, does the problem persist? – molbdnilo Nov 02 '16 at 13:29
  • Check your compiler options (make sure that the source file containing `createDataFolder` and the source file containing `main` are compiled the same - or put the functions in the same source file to remove all doubt). Check your compiler options relating to [calling conventions](http://stackoverflow.com/q/949862/25507) and [ABI](http://stackoverflow.com/q/7492180/25507) in particular. It sounds like `main` may be passing arguments in a way that `createDataFolder` doesn't expect. Looking at the disassembly may help. – Josh Kelley Nov 02 '16 at 13:30
  • 2
    Looks like the case of stack overrun by some variables. Try changing the position of the variable, or just removing all variable prior to that one by one. you may then find the culprit – Daksh Gupta Nov 02 '16 at 13:39
  • 1
    Rather than have a lot of variables as parameters, place the parameters into a structure, then pass the structure by reference. Reduces the load on the stack. – Thomas Matthews Nov 02 '16 at 14:03
  • @MrLister: I don't have any experience using a debugger. Usually, I produce bugs that occur way within numerous nested for loops, since I am writing my own physics simulation program. I should probably start reading into that... – Johann Nov 02 '16 at 21:46
  • @LightnessRacesinOrbit The reason I can't narrow it down to a minimal example is that the error doesn't really occur if I change the code, like I said in the question. – Johann Nov 02 '16 at 21:47
  • @Someprogrammerdude I know, I'm just too lazy to rewrite my code to use structs or something and the parameters become more and more :( – Johann Nov 02 '16 at 21:49
  • @molbdnilo It does not seem to depend on the other code in the function – Johann Nov 02 '16 at 21:56
  • @JoshKelley Thanks, I'll look into that – Johann Nov 02 '16 at 21:56
  • @Dkg Like I said, it works if I change the order of the variables, so your suggestion sounds reasonable – Johann Nov 02 '16 at 21:56
  • @ThomasMatthews Thanks for the hint – Johann Nov 02 '16 at 21:58
  • @Johann: I am absolutely certain that you can narrow it down from what is presented here. All you need to do is be less "lazy". At the very least, you need to make the example _complete_. – Lightness Races in Orbit Nov 02 '16 at 23:35
  • @LightnessRacesinOrbit if I write a small program with a header that only includes the `createDataFolder` function and a main function which only calls the `createDataFolder` function, I don't get the error. – Johann Nov 03 '16 at 09:28
  • So some of you were right to tell me to provide a working example. The bug was inside the `createDataFolder` function. I'll edit the question, so that one of you can tell me exactly what I did wrong when I tried to format a double to a string with a certain size using `sprintf`. – Johann Nov 03 '16 at 09:45
  • @Johann: Then you need to _keep working at it_ until you arrive at a minimal, _complete_ example that **does** reproduce the problem. This is a requirement, not an option! You still haven't done that. Read about [MCVE]s one more time please. – Lightness Races in Orbit Nov 03 '16 at 10:10
  • @LightnessRacesinOrbit _When asking a question about a problem caused by your code, you will get much better answers if you provide code people can use to reproduce the problem._ This is the first sentence in the link you provided. A MCVE is not a requirement. I'm sorry that you don't like the style of my question. Luckily, some other commenters were still able to provide me with some insights. – Johann Nov 03 '16 at 10:28
  • @Johann: Going to side with LRO here; an MCVE is necessary for problems like this, where a compiler bug is implied. – MSalters Nov 03 '16 at 10:33
  • @MSalters Thanks for you input. How is a compiler bug implied here? I thought that `sprintf` simply writes one too many chars somewhere into memory, which is UB – Johann Nov 03 '16 at 10:41
  • That statement is fully accurate, but it's not the _whole_ picture. An MCVE _is_ a requirement; that's just a more-polite-than-necessary, less-clear-than-sufficient way of saying it. – Lightness Races in Orbit Nov 03 '16 at 10:55

1 Answers1

3

in this code:

char range[5];
sprintf(range, "%.3f", potRange);

you pass 10.0 to potRange, so sprintf should produce string "10.000", which is definitely longer than 5. So you have buffer overrun and all effects with that UB. You should use snprintf in such cases to avoid long time spent on debugging side effects:

char range[5];
snprintf(range, sizeof(range), "%.3f", potRange);

it would not make your program correct, but at least problem would become obvious.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • And be generous with buffer sizes. RAM is plenty. – Peter - Reinstate Monica Nov 03 '16 at 13:40
  • 2
    Or, better yet, look up the `ostringstream` class in the standard C++ library, and use it to produce a formatted string instead of `sprintf()`. Among other things, that will mean you don't need to worry about getting buffer lengths right, since that will be taken care of for you. – Peter Nov 03 '16 at 13:46