llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.87k stars 11.93k forks source link

clang-analyzer-valist.Uninitialized warning on use of a copied valist #40656

Open 9bd1cfd0-e1a1-415b-82a2-89ef9b1b5fcb opened 5 years ago

9bd1cfd0-e1a1-415b-82a2-89ef9b1b5fcb commented 5 years ago
Bugzilla Link 41311
Version trunk
OS Linux
CC @Aaron1011,@devincoughlin,@jyn514,@haoNoQ

Extended Description

When running the clang-analyzer checks under clang-tidy, the clang-analyzer-valist.Uninitialized warning is firing on a valist copied using va_copy().

Command: clang-tidy --checks="-,clang-analyzer-" example.cpp

Minimal example.cpp:

include

include

void StringVPrintf(const char* format, va_list ap) { char stack_buf[1024u]; va_list ap_copy; va_copy(ap_copy, ap); vsnprintf(stack_buf, 1024u, format, ap_copy); va_end(ap_copy); }

Clang-tidy warning:

example.cpp:8:5: warning: Function 'vsnprintf' is called with an uninitialized va_list argument [clang-analyzer-valist.Uninitialized] vsnprintf(stack_buf, 1024u, format, ap_copy); ^ example.cpp:8:5: note: Function 'vsnprintf' is called with an uninitialized va_list argument

Aaron1011 commented 3 years ago

I've created a smaller reproduction:

first_file.cpp

extern void my_extern_fn();

void first_fn() {
    my_extern_fn();
}

second_file.cpp

void second_fn(int my_arg, ...) {
    __builtin_va_list args;

    __builtin_va_start(args, my_arg);
    __builtin_va_arg(args, int);
    __builtin_va_end(args);
}

Running clang-tidy-12 first_file.cpp second_file.cpp results in the following output:

Error while trying to load a compilation database:
Could not auto-detect compilation database for file "first_file.cpp"
No compilation database found in /home/aaron/repos/tidy-bug or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
1 warning generated.
/home/aaron/repos/tidy-bug/second_file.cpp:5:5: warning: va_arg() is called on an uninitialized va_list [clang-analyzer-valist.Uninitialized]
    __builtin_va_arg(args, int);
    ^
/home/aaron/repos/tidy-bug/second_file.cpp:5:5: note: va_arg() is called on an uninitialized va_list

Running clang-tidy first_file.cpp or clang-tidy second_file.cpp does not produce any warnings.

jyn514 commented 3 years ago

I'm happy to help debug if you're still having trouble reproducing this.

jyn514 commented 4 years ago

tmp.i Here is the pre-processed C file. The original was

#include<stdarg.h>
#include<stdio.h>
int g(char *format, ...) {
    int len;
    va_list args;
    va_start(args, format);
    len = va_arg(args, int);
    va_end(args);
    return len;
}

I can reproduce locally with cp tmp.c main.c && clang-tidy tmp.c main.c.

haoNoQ commented 4 years ago

I still can't reproduce with multiple files.

Please send us a preprocessed file because different implementations of standard headers on different systems may affect analysis results.

jyn514 commented 4 years ago

As a work-around, you can run clang-tidy on only one file at a time:

$ parallel clang-tidy -- main.c tmp.c   # parallel from `moreutils`, not GNU parallel

That avoids the false positive. (Yes, I'm still running into this a year later.)

jyn514 commented 5 years ago

Not sure what the compile_commands file is, but I have the same problem if I run clang-tidy with more than one source file:

$ cat tmp.c
#include<stdarg.h>
#include<stdio.h>
int f(char *format, ...) {
    int len;
    va_list args;
    va_start(args, format);
    len = vsnprintf((void*)0, 0, format, args);
    va_end(args);
    return len;
}

$ clang-tidy main.c tmp.c
Error while trying to load a compilation database:
Could not auto-detect compilation database for file "main.c"
No compilation database found in /home/joshua/src/c/threaded/src or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
1 warning generated.
/home/joshua/src/c/threaded/src/tmp.c:7:11: error: Function 'vsnprintf' is called with an uninitialized va_list argument [clang-analyzer-valist.Uninitialized,-warnings-as-errors]
    len = vsnprintf((void*)0, 0, format, args);
          ^
/home/joshua/src/c/threaded/src/tmp.c:7:11: note: Function 'vsnprintf' is called with an uninitialized va_list argument
llvmbot commented 5 years ago

I have a similar issue. The warning only arises when there are multiple copies of the source file in the "compile_commands.json" file.

$ cat main.c
#include <stdio.h>
#include <stdarg.h>

void my_fun(int a, const char* fmt, ...) {
    char buf[100];
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, 100, fmt, args);
    va_end(args);
    printf("%s", buf);
}

int main(void) {
    my_fun(42, "%d\n", 1);
    return 0;
}
$ cat compile_commands.json
[
{ "directory": "/home/niklas/projects/c-examples/vprintf",
  "command": "gcc -o main main.c",
  "file": "/home/niklas/projects/c-examples/vprintf/main.c"},
{ "directory": "/home/niklas/projects/c-examples/vprintf",
  "command": "gcc -o main main.c",
  "file": "/home/niklas/projects/c-examples/vprintf/main.c"}
]
$ clang-tidy-8 main.c
1 warning generated.
main.c:8:5: warning: Function 'vsnprintf' is called with an uninitialized va_list argument [clang-analyzer-valist.Uninitialized]
    vsnprintf(buf, 100, fmt, args);
    ^
main.c:8:5: note: Function 'vsnprintf' is called with an uninitialized va_list argument

I hope you can reproduce the issue!

haoNoQ commented 5 years ago

I also cannot reproduce, but this is because in my case builtins aren't recognized at all. I guess we need to make a more consistent solution for recognizing all the builtins.

Xazax-hun commented 5 years ago

Hi!

I unfortunately could not reproduce this problem. What architecture are you using? What standard libraries? Could you also attach a preprocessed file?

As far as I remember, for different target architectures the va_lists have different representation. My suspicion is that, probably not all of the possible representations are handled by the checker currently.

Thanks, Gabor

haoNoQ commented 5 years ago

Gabor, do you know what is this about? :)

9bd1cfd0-e1a1-415b-82a2-89ef9b1b5fcb commented 5 years ago

assigned to @Xazax-hun

philipbliss-progenity commented 2 years ago

I can reproduce this with clang-tidy 14 (installed today from deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main on Ubuntu 20.04)

The file a.c:

#include <stdio.h>

void a(void)
{
    printf("");
}

The file b.c:

#include <stdio.h>

void b(const char *c, ...)
{
    va_list va;
    va_start(va, c);

    vprintf(c, va);

    va_end(va);
}

The command:

clang-tidy-14 a.c b.c

Produces output:

Error while trying to load a compilation database:
Could not auto-detect compilation database for file "a.c"
No compilation database found in /home/pbliss or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
1 warning generated.
/home/pbliss/b.c:8:5: warning: Function 'vprintf' is called with an uninitialized va_list argument [clang-analyzer-valist.Uninitialized]
    vprintf(c, va);
    ^~~~~~~~~~~~~~
/home/pbliss/b.c:8:5: note: Function 'vprintf' is called with an uninitialized va_list argument
    vprintf(c, va);
    ^~~~~~~~~~~~~~