Uninitialized value used but not pointed out

Hi all,

I’m using SonarQube 8.5 to analyze our projects with C code.
The problem and the example code I met showed below.

If i defined two function in the same file

test1.c :

struct test
{
	int i;
	char c;
}

void fun(struct test* t)
{
	if (test->i == 0)        << bug report with garbage value used
		//do something
}

void fun2()
{
	struct test t;
	fun(&t);
}
  • SonarQube will show the garbage value used in fun()

But if I called the structure in the different file as below

test1.c :

struct test
{
	int i;
	char c;
}

void fun(struct test* t)
{
	if (test->i == 0)         << This line will not cause a bug report
		//do something
}

test2.c :

void fun2()
{
	strct test t;
	fun(&t);                  << niether this line.
}
  • Then SonarQube will show no error.

Hello @deron.chen,

What version of the CFamily analyzer do you use? Could you update to the latest version?

I tried to reproduce your problem with your code snippet:

file1.c:

struct test {
  int i;
  char c;
}; 

void fun(struct test* t) {
  if (0 == t->i) {  // Error: The right operand of '==' is a garbage value
    //do something
  }
}      

file2.c:

#include "file1.c"

void fun2() {
  struct test t;
  fun(&t);
}

And I have an error when analyzing file2

Hi @Amelie ,

Thanks for replying.

Not sure what “analyzer” means here, but the version of sonar-cfamily-plugin is

sonar-cfamily-plugin-6.13.0.22261

If it is the “analyzer”, how to update it?
I can’t find the cfamily plugin option on the website in administration >> marketplace.

Hi @Amelie,

I updated some components:

SonarQube from 8.5 to 8.8
sonar-cfamily-plugin from 6.13 to 6.18.0.29274
build-wrapper

Still, my analyzed result did not point out the mentioned error.

Ok, thanks for trying this.
I’ll have a deeper look at it
(and yes, sorry for my wrong choice of words, I meant “plugin” instead of “analyzer”)

1 Like

@Amelie ok, thanks a lot. :grin:

To investigate this further, I would need a reproducer for the false negative (the issue that is not pointed out). Would you be able to do that?

To generate a reproducer file:

  • Add the reproducer option to the scanner configuration:
    sonar.cfamily.reproducer= "Full path to the .cpp file that has or include the file that has the false-negative"
  • Re-running the scanner should generate a file named sonar-cfamily.reproducer in the project folder.
  • Please share this file. If you think this file contains private information I can send you a private message to share it

Hi @Amelie,

can I have two different paths with the option?
the root folder including issues files contains a huge amount of files.

also, need to check with my supervisor if information sharing is allowed.

Hello,

You just need to put the path to the file where you expect an error.
If this error is missing in two files, you can create two different reproducers but I think one will be enough.

By the way, in the second case of your example, are the two files (test1.c) and (test2.c) in the same translation unit? If not, that would explain why we don’t raise an issue: our symbolic execution engine can work cross-files but not cross-translation units. That’s a limitation we have.

Hi @Amelie,

Acording to this operation:

It shows that

The sonar.cfamily.reproducer property was set but no matching file was found. The property was set to:
"/home/sonar/source/test/projects/sources/MY_PROJECT_FILE.cpp"

What do you mean “in the same translation unit”?
In my understanding, every translation unit results in an object file.
Do you mean if I build these two .cpp files to a single object file then it would point out the error?

Hi @Amelie,

I found that I did not describe my example clearly.

I test again with another example, with test.h test.c test1.c test2.c

test.h:

#include <unistd.h>
#include <stdio.h>
struct test
{
    int i;
    char c;
};
void func2(struct test *t);

test1.c:

#include "test.h"
void func4(struct test *t)
{
    if(0 == t->i)
        printf("ti is 0\n");
    else if ('c' == t->c)
        printf("tc ic c\n");
    else
        printf("none");
    t->i = 0;
    t->c = 'a';
}

test2.c:

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "test.h"
void func2(struct test *t)
{
    if (0 == t->i)
        printf("ti is 0\n");
    else if ('c' == t->c)
        printf("tc ic c\n");
    else
        printf("none");
    t->i = 0;
    t->c = 'a';
}

test.c:

#include <stdlib.h>
#include "test1.c"

void func()
{
    struct test t;
    func2(&t);
}

void func1(struct test *t)
{
    if(0 == t->i)
        printf("ti is 0\n");
    else if ('c' == t->c)
        printf("tc ic c\n");
    else
        printf("none");
    t->i = 0;
    t->c = 'a';
}

void func5()
{
    struct test t;
    func4(&t);
}

int main()
{
    func();
    struct test t;
    func1(&t);
    return 0;
}

with Makefile:
gcc -o test test.c test2.c

Here is what I found with the result:

if Undefined struct test t

  1. defined and used in same .c file
    or
    defined in test1.c and include “test1.c” in test.c
    will be pointed as an error.

  2. defined and used in two different files
    include by test.h
    will not be pointed as an error.

Is this what you mean by the limitation?

Hello,

Thanks for the new example, it allowed me to better understand the problem.

To answer your question: yes, that’s exactly what I meant by the limitation.
Basically what happens is the following:
If the function is defined in the same .c file (or directly in the header .h included in the .c file), we are able to inline everything and check correctly the paths so we raise an issue.
But if the function is defined in another .c file, we don’t have access to the body of this function during the symbolic execution so we don’t raise an issue.

1 Like

That solved my problem, thanks for your patient. :laughing:

Best Regards,
Deron.Chen

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.