To get a trial key
fill out the form below
Team License (a basic version)
Enterprise License (extended version)
* By clicking this button you agree to our Privacy Policy statement

Request our prices
New License
License Renewal
--Select currency--
* By clicking this button you agree to our Privacy Policy statement

Free PVS-Studio license for Microsoft MVP specialists
* By clicking this button you agree to our Privacy Policy statement

To get the licence for your open-source project, please fill out this form
* By clicking this button you agree to our Privacy Policy statement

I am interested to try it on the platforms:
* By clicking this button you agree to our Privacy Policy statement

Message submitted.

Your message has been sent. We will email you at

If you haven't received our response, please do the following:
check your Spam/Junk folder and click the "Not Spam" button for our message.
This way, you won't miss messages from our team in the future.

Checking Clang 11 with PVS-Studio

Checking Clang 11 with PVS-Studio

Oct 27 2020

Every now and then, we have to write articles about how we've checked another fresh version of some compiler. That's not really much fun. However, as practice shows, if we stop doing that for a while, folks start doubting whether PVS-Studio is worth its title of a good catcher of bugs and vulnerabilities. What if the new compiler can do that too? Sure, compilers evolve, but so does PVS-Studio – and it proves, again and again, its ability to catch bugs even in high-quality projects such as compilers.


Time for rechecking Clang

To tell you the truth, I wrote this article based on the earlier post "Checking the GCC 10 Compiler with PVS-Studio". So if some paragraphs seem familiar, it's because you've already read them before :).

It's no secret that compilers employ their own built-in static code analyzers, and those are developing as well. That's why we write articles every now and then to show that our static analyzer, PVS-Studio, can find bugs even inside compilers and that we are worth our salt :).

In fact, you can't compare classic static analyzers with compilers. Static analyzers not only detect bugs in source code but also involve a highly developed infrastructure. For one thing, it includes integration with such systems as SonarQube, PlatformIO, Azure DevOps, Travis CI, CircleCI, GitLab CI/CD, Jenkins, and Visual Studio. It includes mechanisms for mass suppression of warnings, which allows you to start using PVS-Studio right off even in a large project. It includes sending notifications by email. And so on and so forth. But the first question developers will still ask is, "Can your PVS-Studio find anything that compilers can't?" And that means we are doomed to write articles about how we check the compilers themselves over and over again.

Let's get back to Clang. There's no need to dwell on the subject and tell you what the project is about. Actually, we checked not only the code of Clang 11 itself but also the code of the LLVM 11 library it's based on. From this article's viewpoint, it doesn't matter if a defect was found in the compiler's or the library's code.

I found the code of Clang/LLVM much clearer than that of GCC. At least it's not teeming with all those awful macros and it extensively employs C++'s modern features.

Even so, the project is still big enough to make examining the analysis report tedious without prior customization. What mostly gets in the way is "semi-false" positives. By "semi-false" positives I mean cases where the analyzer is technically correct to point out certain issues but those warnings are of no practical use. For example, a lot of such warnings refer to unit tests and generated code.

Here's an example for unit tests:

Spaces.SpacesInParentheses = false;               // <=
Spaces.SpacesInCStyleCastParentheses = true;      // <=
verifyFormat("Type *A = ( Type * )P;", Spaces);
verifyFormat("Type *A = ( vector<Type *, int *> )P;", Spaces);
verifyFormat("x = ( int32 )y;", Spaces);
verifyFormat("int a = ( int )(2.0f);", Spaces);
verifyFormat("#define AA(X) sizeof((( X * )NULL)->a)", Spaces);
verifyFormat("my_int a = ( my_int )sizeof(int);", Spaces);
verifyFormat("#define x (( int )-1)", Spaces);

// Run the first set of tests again with:
Spaces.SpacesInParentheses = false;               // <=
Spaces.SpaceInEmptyParentheses = true;
Spaces.SpacesInCStyleCastParentheses = true;      // <=
verifyFormat("call(x, y, z);", Spaces);
verifyFormat("call( );", Spaces);

The analyzer warns us that the variables are assigned the same values they already have:

  • V1048 The 'Spaces.SpacesInParentheses' variable was assigned the same value. FormatTest.cpp 11554
  • V1048 The 'Spaces.SpacesInCStyleCastParentheses' variable was assigned the same value. FormatTest.cpp 11556

Technically, this warning is to the point and the snippet needs simplifying or fixing. But it's also clear that this code is fine as it is and there's no point fixing anything in it.

Here's another example: the analyzer outputs a ton of warnings on the autogenerated file Look at the "wall" of code it contains:


This bulk of code triggers a flood of warnings:

  • V501 There are identical sub-expressions to the left and to the right of the '==' operator: nullptr == nullptr 26
  • V501 There are identical sub-expressions to the left and to the right of the '==' operator: nullptr == nullptr 27
  • V501 There are identical sub-expressions to the left and to the right of the '==' operator: nullptr == nullptr 28
  • and so on – one warning per line...

Yet all that is not a big deal. It can be solved by excluding irrelevant files from analysis, marking certain macros and functions, suppressing certain diagnostic types, and so on. Yes, it can, but it's not a very interesting job to do when you write an article. That's why I did the same thing as in the article about checking the GCC compiler: I kept reading the report until I collected 11 interesting examples to include in the article. Why 11? I just thought that since it was the 11-th version of Clang, I needed 11 examples :).

11 suspicious code snippets

Snippet 1, modulo operation on 1


This is a cool one! I like bugs like that!

void Act() override {
  // If the value type is a vector, and we allow vector select, then in 50%
  // of the cases generate a vector select.
  if (isa<FixedVectorType>(Val0->getType()) && (getRandom() % 1)) {
    unsigned NumElem =
    CondTy = FixedVectorType::get(CondTy, NumElem);

PVS-Studio diagnostic message: V1063 The modulo by 1 operation is meaningless. The result will always be zero. llvm-stress.cpp 631

The programmer is using a modulo operation to get a random value of either 0 or 1. But the value 1 seems to confuse developers and make them write the classic anti-pattern in which the modulo operation is performed on 1 instead of 2. The X % 1 operation is meaningless as it always evaluates to 0. This is the fixed version:

if (isa<FixedVectorType>(Val0->getType()) && (getRandom() % 2)) {

The recently added V1063 diagnostic is awfully simple, but, as you can see, it works perfectly.

We know that compiler developers keep an eye on our work and borrow our ideas. That's totally fine. It's nice to know that PVS-Studio is the driving force behind progress. Let's see how much it will take for a similar diagnostic to appear in Clang and GCC :).

Snippet 2, a typo in a condition

class ReturnValueSlot {
  bool isNull() const { return !Addr.isValid(); }

static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
                                   const FunctionDecl *F2, unsigned NumParams) {
  unsigned I1 = 0, I2 = 0;
  for (unsigned I = 0; I != NumParams; ++I) {
    QualType T1 = NextParam(F1, I1, I == 0);
    QualType T2 = NextParam(F2, I2, I == 0);
    if (!T1.isNull() && !T1.isNull() && !Context.hasSameUnqualifiedType(T1, T2))
      return false;
  return true;

PVS-Studio diagnostic message: V501 There are identical sub-expressions to the left and to the right of the '&&' operator: !T1.isNull() && !T1.isNull() SemaOverload.cpp 9493

The !T1.isNull() check is performed twice. This is obviously a typo; the second part of the condition must check the T2 variable.

Snippet 3, potential array-index-out-of-bounds

std::vector<Decl *> DeclsLoaded;

SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
  unsigned Index = ID - NUM_PREDEF_DECL_IDS;

  if (Index > DeclsLoaded.size()) {
    Error("declaration ID out-of-range for AST file");
    return SourceLocation();

  if (Decl *D = DeclsLoaded[Index])
    return D->getLocation();

PVS-Studio diagnostic message: V557 Array overrun is possible. The 'Index' index is pointing beyond array bound. ASTReader.cpp 7318

Suppose the array stores one element and the value of the Index variable is also 1. Then the (1 > 1) condition is false, and, therefore, the array will be indexed beyond its bounds. Here's the correct check:

if (Index >= DeclsLoaded.size()) {

Snippet 4, argument evaluation order

void IHexELFBuilder::addDataSections() {
  uint32_t SecNo = 1;
  Section = &Obj->addSection<OwnedDataSection>(
      ".sec" + std::to_string(SecNo++), RecAddr,

PVS-Studio diagnostic message: V567 Unspecified behavior. The order of argument evaluation is not defined for 'addSection' function. Consider inspecting the 'SecNo' variable. Object.cpp 1223

Note that the SecNo argument is used twice, getting incremented in the meanwhile. The problem is, you can't tell in what exact order the arguments will be evaluated. The result will, therefore, vary depending on the compiler version or compilation parameters.

Here's a synthetic example to illustrate this point:

#include <cstdio>
int main()
  int i = 1;
  printf("%d, %d\n", i, i++);
  return 0;

Depending on the compiler, this code may output either "1, 1" or "2, 1". I ran it on Compiler Explorer and got the following outputs:

  • when compiled with Clang 11.0.0, the program outputs 1, 1.
  • when compiled with GCC 10.2, the program outputs 2, 1.

Interestingly, this simple case causes Clang to issue a warning:

<source>:6:26: warning:
unsequenced modification and access to 'i' [-Wunsequenced]
printf("%d, %d\n", i, i++);

For some reason, though, this warning wasn't issued on the real code. Either it's disabled as a not very practical one or that case is too complicated for the compiler to cope with.

Snippet 5, a strange duplicate check

template <class ELFT>
void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
                                               const Elf_Shdr *Sec) {

  Expected<StringRef> NameOrErr =
      this->dumper()->getSymbolVersionByIndex(Ndx, IsDefault);
  if (!NameOrErr) {
    if (!NameOrErr) {
      unsigned SecNdx = Sec - &cantFail(Obj->sections()).front();
          "unable to get a version for entry " + Twine(I) +
          " of SHT_GNU_versym section with index " + Twine(SecNdx) + ": " +

PVS-Studio diagnostic message: V571 Recurring check. The 'if (!NameOrErr)' condition was already verified in line 4666. ELFDumper.cpp 4667

The second check is a clone of the first and is, therefore, redundant. Maybe it could be safely removed. But what's more likely is that it contains a typo and was meant to check some other variable.

Snippet 6, potential null pointer dereference

void RewriteObjCFragileABI::RewriteObjCClassMetaData(
  ObjCImplementationDecl *IDecl, std::string &Result)
  ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();

  if (CDecl->isImplicitInterfaceDecl()) {
    RewriteObjCInternalStruct(CDecl, Result);

  unsigned NumIvars = !IDecl->ivar_empty()
  ? IDecl->ivar_size()
  : (CDecl ? CDecl->ivar_size() : 0);

PVS-Studio diagnostic message: V595 The 'CDecl' pointer was utilized before it was verified against nullptr. Check lines: 5275, 5284. RewriteObjC.cpp 5275

When performing the first check, the developer never hesitates to dereference the CDecl pointer:

if (CDecl->isImplicitInterfaceDecl())

But if you look at the code a few lines further, it becomes clear that the pointer can be null:

(CDecl ? CDecl->ivar_size() : 0)

The first check was probably meant to look like this:

if (CDecl && CDecl->isImplicitInterfaceDecl())

Snippet 7, potential null pointer dereference

  NamedDecl *ND = dyn_cast<NamedDecl>(I->NewDecl);
  CXXRecordDecl *ThisContext =
  CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
                              ND && ND->isCXXInstanceMember());

PVS-Studio diagnostic message: V595 The 'ND' pointer was utilized before it was verified against nullptr. Check lines: 2803, 2805. SemaTemplateInstantiate.cpp 2803

This error is similar to the previous one. It's dangerous to dereference a pointer without a prior check when its value is acquired using a dynamic type cast. More than that, subsequent code confirms that such a check is needed.

Snippet 8, a function keeping running despite an error state

bool VerifyObject(llvm::yaml::Node &N,
                  std::map<std::string, std::string> Expected) {
  auto *V = llvm::dyn_cast_or_null<llvm::yaml::ScalarNode>(Prop.getValue());
  if (!V) {
    ADD_FAILURE() << KS << " is not a string";
    Match = false;
  std::string VS = V->getValue(Tmp).str();

PVS-Studio diagnostic message: V1004 The 'V' pointer was used unsafely after it was verified against nullptr. Check lines: 61, 65. TraceTests.cpp 65

The V pointer may be a null pointer. This is obviously an error state, which is even reported with an error message. But the function will just keep running as if nothing happened and will end up dereferencing that very null pointer. The programmer probably wanted the function to stop at this point, in which case it should be fixed as follows:

auto *V = llvm::dyn_cast_or_null<llvm::yaml::ScalarNode>(Prop.getValue());
if (!V) {
  ADD_FAILURE() << KS << " is not a string";
  Match = false;
  return false;
std::string VS = V->getValue(Tmp).str();

Snippet 9, a typo

const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input,
                                  const InputInfo &Output) {
  if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ))
    if (StringRef(A->getValue()) == "single")
      return Args.MakeArgString(Output.getFilename());

  Arg *FinalOutput = Args.getLastArg(options::OPT_o);
  if (FinalOutput && Args.hasArg(options::OPT_c)) {
    SmallString<128> T(FinalOutput->getValue());
    llvm::sys::path::replace_extension(T, "dwo");
    return Args.MakeArgString(T);
  } else {
    // Use the compilation dir.
    SmallString<128> T(
    SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput()));
    llvm::sys::path::replace_extension(F, "dwo");
    T += F;
    return Args.MakeArgString(F);       // <=

PVS-Studio diagnostic message: V1001 The 'T' variable is assigned but is not used by the end of the function. CommonArgs.cpp 873

Look at the last lines of the function. The local variable T changes but isn't used in any way. This must be a typo and the function should probably end as follows:

T += F;
return Args.MakeArgString(T);

Snippet 10, zero as the divisor

typedef int32_t si_int;
typedef uint32_t su_int;

typedef union {
  du_int all;
  struct {
    su_int low;
    su_int high;
    su_int high;
    su_int low;
  } s;
} udwords;

COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {
  if (d.s.low == 0) {
    if (d.s.high == 0) {
      // K X
      // ---
      // 0 0
      if (rem)
        *rem = n.s.high % d.s.low;
      return n.s.high / d.s.low;

PVS-Studio diagnostic messages:

  • V609 Mod by zero. Denominator 'd.s.low' == 0. udivmoddi4.c 61
  • V609 Divide by zero. Denominator 'd.s.low' == 0. udivmoddi4.c 62

I don't know if this is a bug or some tricky contraption, but the code does look strange. It has two regular integer variables, one of which is divided by the other. But the interesting part is that the division operation takes place only if both variables are zeroes. What task is it supposed to accomplish?

Snippet 11, copy-paste

bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(....)
  StringRef FName = II->getName();
  if (FName == "postEvent" &&
      FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
    return true;

  if (FName == "postEvent" &&
      FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
    return true;

PVS-Studio diagnostic message: V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 3108, 3113. MallocChecker.cpp 3113

A code fragment was cloned but never modified afterwards. This clone should either be removed or modified to perform some useful check.



Remember that you can use this free-license option to check open-source projects. We provide other ways to use PVS-Studio for free as well, some of them even allowing analysis of proprietary code. See the full list of options here: "Ways to get a free PVS-Studio license". Thank you for reading!

Further reading on checking compilers with PVS-Studio

Popular related articles
The Last Line Effect

Date: May 31 2014

Author: Andrey Karpov

I have studied many errors caused by the use of the Copy-Paste method, and can assure you that programmers most often tend to make mistakes in the last fragment of a homogeneous code block. I have ne…
Appreciate Static Code Analysis!

Date: Oct 16 2017

Author: Andrey Karpov

I am really astonished by the capabilities of static code analysis even though I am one of the developers of PVS-Studio analyzer myself. The tool surprised me the other day as it turned out to be sma…
PVS-Studio ROI

Date: Jan 30 2019

Author: Andrey Karpov

Occasionally, we're asked a question, what monetary value the company will receive from using PVS-Studio. We decided to draw up a response in the form of an article and provide tables, which will sho…
The way static analyzers fight against false positives, and why they do it

Date: Mar 20 2017

Author: Andrey Karpov

In my previous article I wrote that I don't like the approach of evaluating the efficiency of static analyzers with the help of synthetic tests. In that article, I give the example of a code fragment…
Technologies used in the PVS-Studio code analyzer for finding bugs and potential vulnerabilities

Date: Nov 21 2018

Author: Andrey Karpov

A brief description of technologies used in the PVS-Studio tool, which let us effectively detect a large number of error patterns and potential vulnerabilities. The article describes the implementati…
How PVS-Studio Proved to Be More Attentive Than Three and a Half Programmers

Date: Oct 22 2018

Author: Andrey Karpov

Just like other static analyzers, PVS-Studio often produces false positives. What you are about to read is a short story where I'll tell you how PVS-Studio proved, just one more time, to be more atte…
PVS-Studio for Java

Date: Jan 17 2019

Author: Andrey Karpov

In the seventh version of the PVS-Studio static analyzer, we added support of the Java language. It's time for a brief story of how we've started making support of the Java language, how far we've co…
The Evil within the Comparison Functions

Date: May 19 2017

Author: Andrey Karpov

Perhaps, readers remember my article titled "Last line effect". It describes a pattern I've once noticed: in most cases programmers make an error in the last line of similar text blocks. Now I want t…
Free PVS-Studio for those who develops open source projects

Date: Dec 22 2018

Author: Andrey Karpov

On the New 2019 year's eve, a PVS-Studio team decided to make a nice gift for all contributors of open-source projects hosted on GitHub, GitLab or Bitbucket. They are given free usage of PVS-Studio s…
Static analysis as part of the development process in Unreal Engine

Date: Jun 27 2017

Author: Andrey Karpov

Unreal Engine continues to develop as new code is added and previously written code is changed. What is the inevitable consequence of ongoing development in a project? The emergence of new bugs in th…

Comments (0)

Next comments
This website uses cookies and other technology to provide you a more personalized experience. By continuing the view of our web-pages you accept the terms of using these files. If you don't want your personal data to be processed, please, leave this site.
Learn More →