From fast few days I have been using scan-build to uncover bugs in xfce projects and it's quite effective. Found multiple memory leaks, use-after-free etc. issues.
It would be nice if we could add scan-build to CI itself thus any new code introducing the bug can be caught before merging.
We can continue using gcc. Just need to install scan-build (clang-tools package) in docker container. It'll install clang as dependency but will use gcc for compilation and clang for static analysis.
Or we can add a separate job: Compilation with clang and then use scan-build in that job.
I was wondering if it wouldn't be good, on this occasion, to use both compilers, which sometimes find different warnings (maybe even errors?). I don't know if this is possible at the CI level as it is locally: the second compilation pass with Clang would simply be done during the scan-build (the first one with GCC remains unchanged).
By the way, I was also wondering if it wouldn't be possible to make the pipeline status come out as a warning (orange, not blocking, like you often see e.g. on GNOME's Gitlab) when there are compilation warnings (other than deprecation warnings).
In both the jobs gcc and clang + scan-build we save compiler warnings to 2 separate text files.
We add third job which checks the existence of the warnings in those 2 files and existence of scan-build dir. We set allow_failure: true for this job. And before exiting the script we print which files we detected i.e. which compiler produced warnings, was it scan-build etc.
This way, compiler warnings and scan-build errors will be non-blocking but the failure will show up in pipeline with orange mark.
PS - this means dropping --status-bugs from scan-build commands suggested above.
Why not also include deprecation warnings? Anyways the warnings are non-blocking. And besides it serves as a nice reminder to upgrade the deprecated code.
Yes, actually I agree. I said that a bit "reflexively", because there have already been discussions showing that the subject of deprecation warnings is controversial. But maintainers who want to can very well disable these warnings in their project by various means.
I think we should have -Wall in CFLAGS.
Wouldn't it be best to follow the warnings enabled in xdt-features.m4?
We can have these 2 jobs gcc and clang+scan-build in stage build so that these two will be run in parallel.
And third job (say warnings) in stage test so that this warnings job will be run only when both the gcc and clang+scan-build from build have completed successfully.
We add third job which checks the existence of the warnings in those 2 files and existence of scan-build dir.
On a second thought, may be we should have 3 separate jobs in test stage: gcc-warnings, clang-warnings and scan-build. So that devs don't have to actually click and go through logs to figure out which compiler produced the warnings or was it scan-build etc. Orange mark on gcc-warnings job means gcc produced warnings. Orange mark on scan-build job means there are scan-build errors etc.
So the final jobs layout could be:
gcc: stage: build script: - <existing build commands with `-fanalyzer` in `CFLAGS` saving compiler warnings to gcc-warnings.txt (`2> gcc-warnings.txt`)> artifacts: paths: - gcc-warnings.txtclang: stage: build script: - <scan-build commands suggested above with saving compiler warnings to clang-warnings.txt (`2> clang-warnings.txt`) and output to clang-output.txt (`1> clang-output.txt`)> artifacts: paths: - clang-warnings.txt - scan-build/gcc-warnings: stage: test script: - <check if gcc-warnings.txt exists and has warnings which are not analyzer warnings (`grep 'warning:\|Warning:' gcc-warnings.txt | wc -l` > `grep Wanalyzer gcc-warnings.txt | wc -l`)> - <if true then we can cat gcc-warnings.txt if false then job passed! No gcc warnings!> allow_failure: trueclang-warnings: stage: test script: - <check if clang-warnings.txt doesn't exist> - <if exists then get total no. of warnings from clang-warnings.txt> (`grep warning:\|Warning: clang-warnings.txt | wc -l`) - <get total no. of scan-build warnings generated from clang-output.txt which has line "scan-build: #n bugs found."> - <if `total warnings > scan-build warnings` then job failed `cat clang-warnings.txt`> allow_failure: trueclang-analyzer (scan-build): stage: test script: - <check if scan-build dir doesn't exist> - <if exists then we can ask to checkout `clang` job's artifacts> allow_failure: truegcc-analyzer: stage: test script: - <check if gcc-warnings.txt exists and has analyzer warning (`grep Wanalyzer gcc-warnings.txt`)> - <if yes then we can cat gcc-warnings.txt> allow_failure: true
BTW, there is one small issue with gcc-analyzer and its integration in CI:
gcc-analyzer emits warnings along with other gcc warnings unlike clang which places clang-analyzer (scan-build) warnings separate from other clang warnings.
So, in above jobs scheme where we want to allow gcc-warnings, clang-warnings, gcc-analyzer & clang-analyzer jobs to fail separately ("orange marks") it makes things a bit... not simple for gcc.
What we can do is:
In gcc job, build with -fsanitizer in CFLAGS saving all the warnings in gcc-warnings.txt
In gcc-warnings job, check a. if gcc-warnings.txt exist and b. has warnings which are not analyzer warnings.
i.e. grep 'warning\|Warning' gcc-warnings.txt | wc -l > grep Wanalyzer gcc-warnings.txt | wc -l
In gcc-analyzer job, check a. if gcc-warnings.txt exists and b. has analyzer warning
i.e. grep Wanalyzer gcc-warnings.txt
I'm not sure if there is another clean way to have these separate jobs fail... Anyways, for now I've updated jobs' layout in previous comment. :)
Won't scan-build also write to stderr, so that clang-warnings.txt could be non-empty even when there is no compiler warning? Or does one of the options in your scan-build commands above avoid this? I can't find all these options in the scan-build 13.0.1 manual, by the way.
does one of the options in your scan-build commands above avoid this?
By default, scan-build creates a directory containing HTML report files in /tmp. One can use -o (already done in original post) to select the custom directory.
BTW, this is why script in scan-build job above says "<check if scan-build dir doesn't exist>" :)
I can't find all these options in the scan-build 13.0.1 manual
Run scan-build without any arguments to see all the options. Regarding options missing in docs, I guess MR against scan-build docs is in order. :)
One way to do would be: (The issue is with clang-warnings job only)
In clang build job run scan-build command saving warnings to clang-warnings.txt (2> clang-warnings.txt) and output to clang-output.txt (1> clang-output.txt)
In clang-warnings job get total no. of scan-build warnings from clang-output.txt which has line "scan-build: <n> bugs found." (can use awk, grep, cut etc.)
Then grep warning:\|Warning: clang-warnings.txt | wc -l to get total no. of all the warnings.
If total warnings > scan-build warnings then job failed! cat clang-warnings.txt
PS - I'm deliberately not doing grep "[-W*]" clang-warnings.txt to directly get the clang/gcc warnings as it misses some other build warnings like the ones emitted during doc generation etc.
I recently found out that -fanalyzer -fanalyzer-checker=taint enables additional taint warnings but disables some default warnings from -fanalyzer.
Thanks a lot for picking this up, I had been fooled too. So I'll have to redo a tour of the projects I maintain :) (that also explains why I couldn't find the warning Romain mentioned above about Libxfce4ui).
There should also be a way to exclude false positives, so that they do not pollute the pipeline status until they have been fixed upstream. Probably a pattern file to be added to the repository in a conventional location, on which to then do a grep -vf.
There is --exclude <path-of-dir> option in scan-build but it doesn't provide fine grain control. (Can't exclude specific warning from a file but is useful to exclude third party libs)
I think, your suggestion is very good. we can have exclude-gcc-warnings.txt and exclude-clang-warnings.txt in repo. These files shall simply contain the warning: lines verbatim (of the compiler/analyzer warnings we want to exclude).
Then we can have one additional job (e.g. sanitize-warnings) after build stage and before test stage which will edit the files clang-warnings.txt and gcc-warnings.txt (if they exist) removing all the warnings matching with the warnings specified in respective exclude-*.txt files.
While removing the warnings we should also remove the accompanying lines which follow some warnings. (Just remove all the lines starting from warning: line matched with the one from exclude-*.txt until next warning: line in the same warnings file)
Then in test stage job we can test as suggested above and if the job fails then cat the respective warning file.
BTW this one additional job (say sanitize-warnings) could also separate gcc compiler warnings from gcc analyzer warnings in, say, gcc-compiler-warnings.txt and gcc-analyzer-warnings.txt from one single file gcc-warnings.txt so that when we cat warnings in gcc-warnings job and gcc-analyzer job we only get the respective warnings.
And could also do the same for clang-warnings.txt. So when the clang-warnings job fails we only get to see clang warnings and not analyzer warnings. (cat clang-compiler-warnings.txt)
Though I'm not sure how much of this we need...
But I don't see it being a burden so may be this could indeed be used.