Our website uses cookies to enhance your browsing experience.
Accept
to the top
close form

Fill out the form in 2 simple steps below:

Your contact information:

Step 1
Congratulations! This is your promo code!

Desired license type:

Step 2
Team license
Enterprise license
** By clicking this button you agree to our Privacy Policy statement
close form
Request our prices
New License
License Renewal
--Select currency--
USD
EUR
* By clicking this button you agree to our Privacy Policy statement

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

close form
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

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

close form
check circle
Message submitted.

Your message has been sent. We will email you at


If you do not see the email in your inbox, please check if it is filtered to one of the following folders:

  • Promotion
  • Updates
  • Spam

Webinar: C++ semantics - 06.11

>
>
>
Intermodular analysis

Intermodular analysis

Sep 05 2024

Advanced static analyzers consider data that is passed between procedures/functions. It helps detect more errors and security flaws. It's important when we search for bugs such as buffer overruns, leaked credentials (taint analysis), null dereferences, etc. because resource is often created, used, and released in different functions.

Static analyzers use interprocedural context-sensitive code analysis to detect errors that occur when several procedures interact. If these functions are located in different program modules, the intermodular analysis is to be used.

Take a look at an example of an error detected by the PVS-Studio intermodular analysis in the Midnight Commander project written in C.

Let's start with the widget_destroy function in the widget-common.c file:

void widget_destroy (Widget * w)
{
  send_message (w, NULL, MSG_DESTROY, 0, NULL);
  g_free (w);
}

It's essential that the function releases the memory buffer. Its address is taken from the w argument.

Now let's look at the code in the editcmd.c file:

gboolean edit_close_cmd (WEdit * edit)
{
  Widget *w = WIDGET (edit);
  ....
  widget_destroy (w);     // <= The memory was released here
  if (....) .... else
  {
    edit = find_editor (DIALOG (g));
    if (edit != NULL)
      widget_select (w);  // <= Take a look inside
  }
}

Note that the address of the Widget structure is first passed to the widget_destroy function, where the memory buffer is released. Then, the pointer is passed to the widget_select function that we can see below:

void widget_select (Widget * w)
{
  WGroup *g;
  if (!widget_get_options (w, WOP_SELECTABLE))
    return;
  ....
}

It just passes the pointer to the widget_get_options function:

static inline gboolean
widget_get_options (const Widget * w, widget_options_t options)
{
  return ((w->options & options) == options);
}

Here, we have reached the point where undefined behavior occurs because of data being used in the already released memory buffer. The PVS-Studio analyzer issues a warning:

V774 The 'w' pointer was used after the memory was released.

This is a rather simple case where we use only two files: widget-common.c and editcmd.c. Errors can also be detected in longer call chains spread across three or more files. However, in reality, static analyzers are limited in the call analysis depth. The limits are both theoretical (halting problem) and practical (high-computational complexity). So, it's a good idea to combine static and dynamic code analysis.

Additional links

Popular related articles


Comments (0)

Next comments next comments
close comment form