Exercising valgrind

Goal: I will learn to use valgrind for tracking the problems with memory management, and to interpret the output of valgrind.

This is important because, in the remaining projects, one requirement is that the submitted program has no problems with memory management. You are supposed to make sure that there are none by using valgrind during the test phase.

Instructions: Take the code template: wk04_trees/valgrind at hand.

Let us examine this small program. You can see several problems to do with memory management right away:

#include <iostream>

using namespace std;

int main() {
    int number1;
    int number2 = 111;
    int *ptr1 = new int;
    int *ptr2 = new int(222);

    cout << number1 << " "
         << number2 << " "
         << *ptr1 << " "
         << *ptr2 << endl;

    delete ptr1;

    *ptr1 = 333;
}

In this assignment, you will compare using valgrind between Qt Creator and command line.

Executing valgrind in Qt Creator

In Qt Creator, open the project valgrind.pro in wk04_trees/valgrind.

If you want, you can execute the program. In the Application Output window, there should be the output ”exited with code 0”, that is, the execution of the program finished with the return value EXIT_SUCCESS, which means that everything went well (despite the program containing basically nothing but errors). Please note that when a program has as many problems with memory management as does our example program, it is not guaranteed that it will execute without hiccups. When the personnel created the assignment, it was possible to execute the program all the way to the end with the compiler installed on linux-desktop, but we cannot guarantee that it works similarly in all environments.

Execute valgrind by selecting Analyze > Valgrind Memory Analyzer. The program starts, but this time, the Application Output window will contain the output ”Analyzing finished”.

Also, Qt Creator opens the window Memcheck, and in its black top bar, it is supposed to say ”Memory Analyzer Tool finished, 8 issues were found”. We will examine the contents of that window in this assignment. If your Qt Creator shows nothing below the titles Issue and Location, click the filter icon located in the black top bar of the window and put a check on ”External Errors”. This will make the 8 problems valgrind found appear on the list.

Executing valgrind on the command line

Start the command line user interface and navigate into the directory where you saved the abovementioned program code (the project directory of the previous section).

  1. Compile your source code manually by writing the compilation command into the Linux command line:

    g++ -std=c++17 -Wall -g main.cc
    

    When compiling C or C++ programs with -g, the compiler includes additional metadata about the source code, such as variable names, function names, and line numbers. This debugging information is crucial for Valgrind to provide more informative and accurate output during memory profiling and error detection. Thus, Valgrind can trace memory operations back to the original source code, making it easier to identify the locations of memory issues.

    If your source code contained no errors, the result will be the executable program (a file in machine language) called a.out.

  2. If you want, you can try executing the program by writing this command on the Linux command line:

    ./a.out
    
  3. Then execute valgrind command for the compiled program:

    valgrind --quiet --leak-check=full ./a.out
    

    If there are no memory problems in that program, there will be no extra outputs on your screen aside from the outputs of your program.

    Because this example program did contain problems with memory management, valgrind prints an enormous amount of information, and we will now take a good look at it. You need to see the output from the very beginning, so scroll the terminal upwards far enough for you to see the valgrind command you wrote. (Tip: you also could stretch the terminal window as long as you can for easier working.)

Set Qt Creator and the terminal window side by side on your screen so that you can see both of them. This will make your work easier.

Different outputs of Qt Creator and the command line

Let us first examine the problem titled by valgrind as ”Use of uninitialized value of size 8”. Find it in Qt Creator, you can see the output on the command line.

At the beginning of each line, there is writing like this ”==6647==”. The number is the process id (pid), which is different in each execution. In addition, some lines may contain something like this ”at 0x4F31BE3:”. Qt Creator does not display this information as it is mostly irrelevant.

If you ignore the difference described above, is there an essential difference in the output valgrind gives you, depending on how you executed it?

Contents of the column Location

In the Memcheck window of Qt Creator, there are two columns: Issue and Location. To access the Location column after clicking a downwards arrow to expand one of the long lines and view its contents, you can:

Using an uninitialized variable

The error messages generated by valgrind may not always be straightforward, making it challenging to interpret them correctly. However, by observing how valgrind produces different messages for various issues in this simple program snippet, you can improve your understanding of them.

To achieve this, analyze the code and the error messages it generates. Specifically, explore the type of error message valgrind provides when encountering an uninitialized variable.

Not deallocating memory

What is the error message valgrind gives you for not deallocating memory?

Using memory you already deallocated

What is the error message valgrind gives you for using memory you already deallocated?

Executing valgrind command

Static analysis means that you analyze program code without executing it. Dynamic analysis, however, means that you analyze the working of a program in a certain execution situation (with certain inputs, for example). The dynamic analysis only finds the errors that the execution in question reveals.

What can you deduce from the fact that Qt Creator starts up the execution of a program in the process window every time you execute the valgrind analysis to a program?

Detecting invalidated iterator

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {10, 20, 30};
    auto it = numbers.begin() + 1; // Iterator points to the second element

    numbers.insert(numbers.begin(), 5); // Insert a new element at the beginning

    // Attempt to access the value pointed by the invalidated iterator
    int value = *it;

    return 0;
}

In the code above, an iterator it is obtained for the second element of a vector. A new element is inserted at the beginning of the vector, causing the iterator it to become invalidated. Which type of error detected by Valgrind is likely to occur due to the use of the invalidated iterator?

Command line switches

Again, execute valgrind from the command line. This time, your command should be:

valgrind --verbose --leak-check=full ./a.out

i.e. instead of the switch --quiet, you will use the switch --verbose. How does that affect your print?

Irreflexive requirements error

Is caused by:

Irreflexive requirements error

std::vector<std::pair<AffiliationID, Coord>> aff_coords;

inline bool operator<<(Coord c1, Coord c2)
{
    return (c1.x * c1.x + c1.y * c1.y <= c2.x * c2.x + c2.y * c2.y);
}


sort(aff_coords.begin(), aff_coords.end(),
  [](auto a, auto b) {return a.second << b.second;});

How to fix?

Using the command line, continuation

The programming professionals state that: ”Some options of the build-tools you need in serious development are easily accessible only via the command line. Graphical integrations are usually not developed as fast as I would need them, if at all.”

What does this mean in practice? For example, on the matter of analyzing errors of memory management, it means that when valgrind was published, it was only used on the command line. Qt Creator’s valgrind connection was implemented at a later stage.

The companies often want to use the newest tools, which means it is important for a professional to know how to use the command line.

Finally, try running in Qt Creator Analyze > Valgrind Memory Analyzer with GDB. You’ll notice that this launches the valgrind tool in debug mode, allowing you to step through the program code line by line, as usual in a debugger. Now, in the Application Output window, you’ll find output similar to what you would see in the terminal window.

When you finish, make sure to close the debugger!

Most of the time, Qt Creator switches from Edit mode to Debug mode when you execute the valgrind command. Sometimes it may happen that Qt Creator does not behave this way, and instead, to see the Memcheck window, you need to manually switch from Edit mode to Debug mode. When this ”feature” (?) occurs, it’s important to understand that valgrind is always executed in Debug mode within Qt Creator.