1

I have the following code:

struct branchInfo{
    Quaternion r;
    Vector3 p;

    std::vector<Vector3> branchPoints;
};

std::vector<Vector3> LSystem::Turtle(){

    std::vector<branchInfo> b;

    // The axiom should always start with a '[' at the start and a ']' at the end
    for(unsigned int i = 0; i < axiom.length(); i++) {
        char c = axiom[i];

        if (c == '[') {
            branchInfo temp;

            temp.r = rotationQuat;
            temp.p = position;
            temp.branchPoints.push_back(position);

            b.push_back(temp);
        } else if (c == ']') {
            branchInfo temp = b.back();

            rotationQuat = temp.r;
            position = temp.p;
            branches.push_back(temp.branchPoints);

            b.pop_back();
        } else {
            // Evaluate the character and move the turtle
            // F = move forward according to pitched, rolled, and yawed axis
            // f = move backward according to pitched, rolled, and yawed axis
            // p = pitch -45 degrees
            // P = pitch +45 degrees
            // r = roll -45 degrees
            // R = Roll +45 degrees
            // y = yaw -45 degrees
            // Y = yaw +45 degrees
            // [ = start new branch
            // ] = end new branch

            switch(c) {
            case 'f':
                b.back().branchPoints.push_back(Forward(-1.5f));
                break;
            case 'F':
                b.back().branchPoints.push_back(Forward(1.5f));
                break;
            case 'p':
                Pitch(-angle);
                break;
            case 'P':
                Pitch(angle);
                break;
            case 'r':
                Roll(-angle);
                break;
            case 'R':
                Roll(angle);
                break;
            case 'y':
                Yaw(-angle);
                break;
            case 'Y':
                Yaw(angle);
                break;
            }
        }
    }
}

The point of this code is to evaluate the axiom string which the turtle will follow. This is an L-system and part of the point of an L-system is to have branching and that occurs when there is a '[' character which means the rotation and position get saved and will be used later. As an example, If my L-system class contains the string "[PPPPrrFp[[X]PX]pXRR]" I will get the following error: *** Error in /home/user/program/dist/Debug/GNU-Linux/world': double free or corruption (fasttop): 0x0000000003f43240 ***

I know it is not easy to step-by-step go through this program and I don't expect anyone to do that. I'm just wondering if it is easy to see what is wrong with the program. I understand that the error probably has to do with using some of the std::vector methods/functions but I'm am not seeing why or how it is causing it.

Also, it is not consistent. Sometimes the program will run and without a hitch, and other times it will crash with the error I mentioned.

Functions for Yaw, Pitch, and Roll should not matter.

From what I have googled, I can only ever find examples of this error when dealing with classes that have constructors, destructors, and when deleting arrays, etc.

Thanks for any help! I hope it is obvious what is happening and doesn't take too much time. If it does look like it will take too long then do not bother. Thanks again.

EDIT: To make it eaiser to understand what is happening in the function, I will do a step-by-step explanation of the function: Start at index 0 of the axiom string and check if it starts a new branch ('['), and if it does then push/save 3D vector pos and rot -> if the current char is not an '[' or ']' then move pos or rotate -> if the branch ends (']') resusme from the last saved pos and rot, and pop the top of the stack -> keep going for every char in the string.

Community
  • 1
  • 1
JustHeavy
  • 235
  • 1
  • 2
  • 8
  • 3
    It's probably related to the `Vector3` class not having a set of constructors, destructor, and assignment operators that work together correctly. Look up rule of three (before C++11), rule of five (C++11 or later), and rule of zero (also C++11 or later). – Peter May 23 '18 at 23:58
  • Got it. That class comes from a library that I am using. I will look into it. Thank you. – JustHeavy May 23 '18 at 23:59
  • 1
    Whats in Axiom[]? – solarflare May 24 '18 at 00:00
  • 1
    Although there can be bugs in implementation of `std::vector`, such code with most compilers is normally pretty well verified. But `std::vector` ASSUMES the objects it contains play right. – Peter May 24 '18 at 00:00
  • 1
    Assuming the library you got `Vector3` from is even remotely sane, it should comply with the rule of 3/5/0 and shouldn't cause any problems with used with `std::vector`. The problem is somewhere else, in code you didn't show us. – HolyBlackCat May 24 '18 at 00:02
  • Sorry @solarflare. It contains the string that I mentioned: [PPPPrrFp[[X]PX]pXRR] Which includes the square-brackets at the start and end. – JustHeavy May 24 '18 at 00:03
  • 1
    @Peter the Rule of Zero isn't new in C++11. Even RuleOf3 classes in pre-C++11 compilers should strive for RuleOf0 whenever possible. – Remy Lebeau May 24 '18 at 00:05
  • 1
    Why you do `if/else` and then switch on the same variable? Just use one switch. – Slava May 24 '18 at 00:11
  • @Slava Very good point and I do not think I could explain it. I got desperate looking for a reason why I'm getting the error in my post and was playing around with something. I see that it does not make sense. – JustHeavy May 24 '18 at 00:14
  • 1
    validate at least on processing ']' that `b` is not empty. Also get a stack trace on failure - it should give idea where problem is. – Slava May 24 '18 at 00:16
  • 1
    @JustHeavy What does `X` do in your axiom? `'X'` is not in your `switch` block. Does X manipulate the contents of `b` or the members of `this` in any way? In addition to what Slava said, make sure that `f` and `F` also validate that `b` is not empty before calling `back()`. – Remy Lebeau May 24 '18 at 00:19
  • Turns out that @Peter was more correct. His comment led me to getting rid of any instance of the Vector3 class. Turns out that changing `std::vector LSystem::Turtle()` to `void LSystem::Turtle()` solved all my problems. – JustHeavy May 24 '18 at 00:29
  • 1
    @JustHeavy you weren't `return`ing a valid vector to begin with, so if the caller tried to use that return value, it would have undefined behavior. On a side note, it looks like `LSystem::branches` and `branchInfo::branchPoints` can be eliminated. `branches` doesn't seem to be used for anything, so what is the point of it? When you encounter a `[`, save just the current rotation/position only, and have `]` restore them. Done. Accordingly to your commented requirements, `f` and `F` should be manipulating the turtle's current `position`, not caching them off to the side, isn't that right? – Remy Lebeau May 24 '18 at 00:30
  • 2
    @JustHeavy it is unrelated to `Vector3` - problem is you are missing return statement. You should read warnings. Of course changing function return type to `void` solved that problem. – Slava May 24 '18 at 00:31
  • Corrent. There may be fragments from some of my older code where I was not using a struct to represent my branches. I will get to fixing/cleaning. Thanks for your time @RemyLebeau. – JustHeavy May 24 '18 at 00:32
  • 1
    @RemyLebeau there is UB unrelated to if caller using return value or not. – Slava May 24 '18 at 00:34
  • @Slava I see that now. The only errors I had were ones that gave me a readout of the memory and the one that I mentioned. Those may contain information that you understand but to me it was not clear. Sorry that I wasted your time. I did spend a lot of time trying to solve this myself; I used the debugger and stepped through the program one step at a time, I googled the error, I read the error and really tried to understand it. I only came here as a last resort. – JustHeavy May 24 '18 at 00:35
  • 1
    @JustHeavy I am not talking about runtime error, I am talking about compilation warnings. Compiler should warn you that function must return a value. Even better if you make compiler to treat that as error, not warning. – Slava May 24 '18 at 00:38
  • @Slava I see. My compiler (g++/gcc) did not give me any warnings and my IDE (Netbeans) did not display them (most likely the complier's fault, I would think or maybe it is in my settings). The only way I would have known/remembered this is from when I read my C++ textbook long ago, but sadly it has been awhile since then and I have not used C++ much since then. Thank you again for your time, this interaction has taught me a lot. I should probably go review my text once again. – JustHeavy May 24 '18 at 00:43
  • 1
    @JustHeavy: Compile with `-Wall` (and `-Werror` if you want to fail hard). If you're really looking for completely clean code, `-Wextra` will turn on really nitpicky warnings, but `-Wall` usually covers the major correctness issues. – ShadowRanger May 24 '18 at 00:52

1 Answers1

0

In case someone from the future comes across this problem. What I was doing wrong was not returning anything in my function even though I specified a non-void return type for the function. Changing the return type to void solved my problem.

JustHeavy
  • 235
  • 1
  • 2
  • 8
  • FYI: there are compiler warnings to detect these kind of issues, they can save you a lot of time – JVApen May 24 '18 at 06:29