Memory leak not detected

Hello,

I am using Developer Edition

  • Version 8.4.2 (build 36762), and it has CFamily Code Quality and Security v6.8.
    However, it cannot detect the memory leak.
    Below is my sample code:
int main()
{
	int N1 = 3;
	double pWTruth[ ] = { 40640.4977, 17411.3202, 921.4525 };
	double * * ppA = (double **)malloc( 3 * sizeof( double * ) );
        return 0;
}

As recommended I use the build wrapper with a cmake build.
And then run the sonar_scanner on using the build wrapper output.

Hello @mail2cuc ,

I tried your code, and the memory leak was reported. Can you provide more context about how you analyzed it? Was it in a file of its own with just the lines you’re sending us?

Could you provide us with an analysis log?

Thank you!

Hi

Below is the way I scan and after that is the complete code. I am also attaching the log.build-wrapper.log (415.4 KB)
I run as below: runtests.sh include commands for cmake build and run the unit tests.
build-wrapper-linux-x86-64 --out-dir bw_output bash ./ci/c/bin/runtests.sh Release
sonar-scanner -Dsonar.login=${SONAR_LOGIN} -Dsonar.host.url=https://sonarqube***.com

When I run the build wrapper the unit tests are run which i can see. Then the scanner reports the static code analysis eg. error that ‘rv’ variable overwritten. But not the memory leak in it.

#include <unity.h>
#include <unity_internals.h>
#include <unity_fixture.h>

double * AllocDoubleVector
(
  int length
)
{
  double *pDoubleVector = (double *)calloc( length, sizeof( double ) );
  return pDoubleVector;
}

double ** AllocDoubleMatrix
(
  const int n1,
  const int n2
)
{
  int i;
  double **ppDoubleMatrix = (double **)malloc( n1 * sizeof( double * ) );
  for ( i = 0; i < n1; i++ )
  {
    ppDoubleMatrix[i] = AllocDoubleVector( n2 );
  }
  return ppDoubleMatrix;
}

static int testMemoryLeak()
{
  int N1 = 3;
  int N2 = 3;
  int seed = 0;
  int rv = 0;

  // reference vectors and matrices
  double pWTruth[] = { 40640.4977, 17411.3202, 921.4525 };  
  double * * ppA = AllocDoubleMatrix(N1, N2);  
  double * * ppV = AllocDoubleMatrix(N1, N2);
  double * pW    = AllocDoubleVector(N1);
  SetRandomDoubleMatrix(ppA, N1, N2, seed);
  SvdDouble(ppA, N1, N2, pW, ppV);
  rv = checkErrorDouble(pW, pWTruth, N1, __FUNCTION__, 1e-12);
  rv = 0;
  return rv;
}

TEST(MatrixUtilsTest, testMatrixUtils)
{
  TEST_ASSERT_EQUAL(0, testMemoryLeak());
}

Thank you.

Hello again @mail2cuc,

This code is significantly different from the one you provided previously. You are passing the memory you allocated to some functions, and unless the code of those function is inline, there is now way for us to tell if those functions are going to free the memory or not (we are not performing cross translation unit analysis for this rule).

As a consequence, we hope for the best, and won’t report those memory leaks, because we cannot prove that they exist.

By the way, you did not provide me the analysis log (running the sonar-scanner with a -X option), but with the build wrapper log.The logs can be interesting because if there are some parsing errors in the project, this can be another reason why advanced bugs such as leak detection might be skipped. But as I said earlier, there is no need for that here to explain why we don’t report a memory leak.

Hope this helps,

Thank for your reply Joly. I figured out. sonarcfamily can detect memory leak in a simple hello world tutorial examples but not really in product code. Please see my comments and question embedded in the code below.

Below are the examples:

#include "iostream"
#include "stdlib.h"

using namespace std;

int sum(double *const *const A, double *const *const B, int N1, int N2){
	double sum = 0;
	for (int i = 0; i < N1; i++)
	{
		for (int j = 0; j < N2; j++)
		{
			sum += A[i][j] + B[i][j];
		}
	}
	return 0;
}

// both sonarcfamily and valgrind detects leak here
int testMemoryLeakA()
{
	int N1 = 3;
	int N2 = 3;

	double pWTruth[] = { 40640.4977, 17411.3202, 921.4525 };
	int i;
    double **ppA = (double **)malloc( N1 * sizeof( double * ) );

	for ( i = 0; i < N1; i++ )
	{
		ppA[i] = (double *)calloc( N2, sizeof( double ) );
	}
	
	double **ppV = (double **)malloc( N1 * sizeof( double * ) );

	for ( i = 0; i < N1; i++ )
	{
		ppV[i] = (double *)calloc( N2, sizeof( double ) );
	}

    return 0;
}

// sonarcfamily cannot detect the leak here simply because sum() function was called. should sonarcfamily detect leak here as well? What am i doing wrong.
// valgrind detects the leak here as well.
int testMemoryLeakB()
{
	int N1 = 3;
	int N2 = 3;

	double pWTruth[] = { 40640.4977, 17411.3202, 921.4525 };
	int i;
    double **ppA = (double **)malloc( N1 * sizeof( double * ) );

	for ( i = 0; i < N1; i++ )
	{
		ppA[i] = (double *)calloc( N2, sizeof( double ) );
	}
	
	double **ppV = (double **)malloc( N1 * sizeof( double * ) );

	for ( i = 0; i < N1; i++ )
	{
		ppV[i] = (double *)calloc( N2, sizeof( double ) );
	}

    return sum(ppA, ppV, N1, N2);
}

int main ()
{
   testMemoryLeakA();
   testMemoryLeakB();
   cout << "Hello World!";
   return 0;
}

This is an overstatement. We can detect some memory leaks, included in production code. We cannot detect all of them (and no tool can do that, it’s just proven to be impossible). We have a limitation that we cannot currently follow the execution flow through a different file.

It’s not only that a sum function is called, it is also that this function takes the pointer as an argument, so we have to assume that maybe it does free the memory. You are not doing anything wrong, this is just a limitation of our product.

Valgrind works in a totally different way, by instrumenting code under execution. Which means for instance that to discover a memory link, you need to actually run the code where it happens. We don’t have this constraint. Different tools, different trade-offs. Our advice is to use a combination of tools to benefit from the strengths of all of them.

Thanks Joly and for the recommendation to use multiple tools.
I earlier used sonarqube community edition and all the open plugins are supported eg. c, cxx.
Now I migrated to sonarqube developer edition and these plugins are no more supported? How can I export a valgrind report to a sonarqube developer server? Do I need to use the generic import format or is there an easier way?

Hello @mail2cuc ,

The developer edition supports plugins, but since only one analyzer can analyze each file, our analyzer for C++ might not work together with sonar-cxx. Since we do not support this product, you should ask to its maintainers if it is possible to make it work together with our analyzer.

Anyways, as you said, it is also possible to import generic reports, as explained in Generic Issue Import Format | SonarQube Docs. If you want to import valgrind reports into SonarQube, this could be the way to do it.

Best regards,