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

Request our prices
New License
License Renewal
--Select currency--
USD
EUR
GBP
RUB
* 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.

>
>
>
Asterisk: PVS-Studio Takes Up Telephony

Asterisk: PVS-Studio Takes Up Telephony

Aug 26 2014

Asterisk is a software implementation of a telephone private branch exchange (PBX); it was created in 1999 by Mark Spencer of Digium. Like any PBX, it allows attached telephones to make calls to one another, and to connect to other telephone services, such as the public switched telephone network (PSTN) and Voice over Internet Protocol (VoIP) services. Its name comes from the asterisk symbol, *.

Asterisk is released under a dual license model, using the GNU General Public License (GPL) as a free software license and a proprietary software license to permit licensees to distribute proprietary, unpublished system components.

In this article, we are going to discuss the results of the check of the Asterisk project by PVS-Studio 5.18.

The project seems to be regularly checked by the Coverity analyzer, which is indicated by comments like this one:

/* Ignore check_return warning from Coverity for ast_exists_extension below */

However, I still found some disappointing typos in the code. Let's try to figure them out as well as other potential issues. The source code was downloaded from the project's SVN repository.

0276_asterisk/image1.png

Typo #1

V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 2513, 2516. chan_sip.c 2516

static void sip_threadinfo_destructor(void *obj)
{
  struct sip_threadinfo *th = obj;
  struct tcptls_packet *packet;

  if (th->alert_pipe[1] > -1) {            // <=
    close(th->alert_pipe[0]);
  }
  if (th->alert_pipe[1] > -1) {
    close(th->alert_pipe[1]);
  }
  th->alert_pipe[0] = th->alert_pipe[1] = -1;
  ....
}

In this code, the programmer intended to check the states of pipes 0 and 1, after which they should be closed, but the typo prevents the state of pipe 0 from being checked. The reason why the code runs well for a long time is probably that both pipes are used in most cases.

Typo #2

V503 This is a nonsensical comparison: pointer < 0. parking_manager.c 520

static int manager_park(....)
{
  ....
  const char *timeout = astman_get_header(m, "Timeout");
  ....
  int timeout_override = -1;
  ....
  if (sscanf(timeout, "%30d", &timeout_override) != 1 ||
    timeout < 0) {                                          // <=
      astman_send_error(s, m, "Invalid Timeout value.");
      return 0;
  }
}

In this fragment, a pointer is meaninglessly compared to zero. I guess the programmer wanted to check the timeout_override variable returned by the sscanf function.

Typo #3

V568 It's odd that the argument of sizeof() operator is the 'data[0] * 2' expression. channel.c 8853

static int redirecting_reason_build_data(....)
{
  ....
  if (datalen < pos + sizeof(data[0] * 2) + length) {       // <=
    ast_log(LOG_WARNING, "No space left for %s string\n", label);
    return -1;
  }
  ....
}

The sizeof() operator calculates the expression type and returns the size of this type while the expression itself fails to be calculated. Complex expressions usually indicate that the code contains an error, which errors are most often caused by typos. This is just the case in the example above: multiplication by two was most likely meant to be outside the parentheses of the sizeof() operator.

Typo #4

V653 A suspicious string consisting of two parts is used for array initialization. It is possible that a comma is missing. Consider inspecting this literal: "KW_INCLUDES" "KW_JUMP". ael.y 736

static char *token_equivs1[] =
{
  ....
  "KW_IF",
  "KW_IGNOREPAT",
  "KW_INCLUDES"          // <=
  "KW_JUMP",
  "KW_MACRO",
  "KW_PATTERN",
  ....
};

static char *ael_token_subst(const char *mess)
{
  ....
  int token_equivs_entries = sizeof(token_equivs1)/sizeof(char*);
  ....
  for (i=0; i<token_equivs_entries; i++) {
    ....
  }
  ....
}

When declaring an array of string literals, two strings get united into one. This error may be a consequence of a typo when a comma is missing between the string literals.

This is what the items of the token_equivs1 array actually look like:

0276_asterisk/image2.png

Another issue of that kind:

  • V653 A suspicious string consisting of two parts is used for array initialization. It is possible that a comma is missing. Consider inspecting this literal: "includes" "jump". ael.y 776

Typo #5

V501 There are identical sub-expressions 'strcasecmp(item->u1.str, "endwhile") == 0' to the left and to the right of the '||' operator. pval.c 2513

void check_pval_item(pval *item, ....)
{
  ....
  if (strcasecmp(item->u1.str,"GotoIf") == 0
      || strcasecmp(item->u1.str,"GotoIfTime") == 0
      || strcasecmp(item->u1.str,"while") == 0
      || strcasecmp(item->u1.str,"endwhile") == 0           // <=
      || strcasecmp(item->u1.str,"random") == 0
      || strcasecmp(item->u1.str,"gosub") == 0
      || strcasecmp(item->u1.str,"gosubif") == 0
      || strcasecmp(item->u1.str,"continuewhile") == 0
      || strcasecmp(item->u1.str,"endwhile") == 0           // <=
      || strcasecmp(item->u1.str,"execif") == 0
      || ....)
  {....}
}

One of the expressions in the cascade of conditional operators is repeated twice. One can never guarantee that a typo hasn't affected some very important condition.

Identical comparisons

V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 851, 853. manager_channels.c 851

static void channel_hangup_handler_cb(....)
{
  const char *event;
  ....
  if (!strcmp(action, "type")) {
    event = "HangupHandlerRun";
  } else if (!strcmp(action, "type")) {
    event = "HangupHandlerPop";
  } else if (!strcmp(action, "type")) {
    event = "HangupHandlerPush";
  } else {
    return;
  }
  ....
}

This is a highly suspicious fragment: what is done here is either assigning the "HangupHandlerRun" string to the 'event' variable or leaving the function.

Always false

V547 Expression is always false. Unsigned type value is never < 0. enum.c 309

static int ebl_callback(....)
{
  unsigned int i;
  ....
  if ((i = dn_expand((unsigned char *)fullanswer,
     (unsigned char *)answer + len,
     (unsigned char *)answer, c->apex, sizeof(c->apex) - 1)) < 0)
  {
    ast_log(LOG_WARNING, "Failed to expand hostname\n");
    return 0;
  }
}

The 'i' variable is unsigned and will never be less than zero. The dn_expand() function returns value -1 in case of failure, so the 'i' variable cannot be 'unsigned'.

Insidious optimization

V597 The compiler could delete the 'memset' function call, which is used to flush 'buf' buffer. The RtlSecureZeroMemory() function should be used to erase the private data. channel.c 7742

static int silence_generator_generate(....)
{
  short buf[samples];

  struct ast_frame frame = {
    .frametype = AST_FRAME_VOICE,
    .data.ptr = buf,
    .samples = samples,
    .datalen = sizeof(buf),
  };
  frame.subclass.format = ast_format_slin;
  
  memset(buf, 0, sizeof(buf));      // <=
  ....
}

Since the 'buf' array is not used anywhere after calling the 'memset' function, the compiler may remove the call for optimization's sake, and the array will not be cleared, as planned by the programmer.

Users tend to misunderstand the V597 warning. Here you are some references to figure out what the issue this diagnostic points out is all about:

Pointers

V595 The 'object_wizard->wizard' pointer was utilized before it was verified against nullptr. Check lines: 683, 686. sorcery.c 683

static void sorcery_object_wizard_destructor(void *obj)
{
  struct ast_sorcery_object_wizard *object_wizard = obj;

  if (object_wizard->data) {
    object_wizard->wizard->close(object_wizard->data);      // <=
  }

  if (object_wizard->wizard) {                              // <=
    ast_module_unref(object_wizard->wizard->module);
  }

  ao2_cleanup(object_wizard->wizard);                       // <=
}

For some reason, this code selectively checks the pointer for being null. Places like this usually indicate that there is some probability that a null pointer may get into the function, so it should be checked in all the related places before using it.

Excessive code

I don't think the next two samples are errors, but they can be simplified.

V584 The '1' value is present on both sides of the '==' operator. The expression is incorrect or it can be simplified. chan_unistim.c 1095

static void check_send_queue(struct unistimsession *pte)
{
  if (pte->last_buf_available == 1) {
    ....
  }
  else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {  // <=
    ....
  }
}

Incrementing the arguments by one to both sides of the equal sign doesn't seem to make much sense.

V571 Recurring check. The 'wizard->wizard->retrieve_fields' condition was already verified in line 1520. sorcery.c 1521

void *ast_sorcery_retrieve_by_fields(....)
{
  ....
  if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
  ....
  } else if (fields && wizard->wizard->retrieve_fields) {  // <=
      if (wizard->wizard->retrieve_fields) {               // <=
        object = wizard->wizard->retrieve_fields(....);
      }
  }
}

It's not an error, but one of the pointer checks can surely be removed.

Conclusion

Using static analysis regularly will help you save quite a lot of time you could spend on solving more useful tasks than catching silly mistakes and typos.

Also, see the interesting article The Last Line Effect about typos.

Popular related articles
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…
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…
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…
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…
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…
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…
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…
The Ultimate Question of Programming, Refactoring, and Everything

Date: Apr 14 2016

Author: Andrey Karpov

Yes, you've guessed correctly - the answer is "42". In this article you will find 42 recommendations about coding in C++ that can help a programmer avoid a lot of errors, save time and effort. The au…
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…

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 →
Accept