Skip to main content

IAR Embedded Workbench for Arm 9.70.x

CERT-MSC39-C

In this section:
Synopsis

Do not call va_arg() on a va_list that has an indeterminate value

Enabled by default

Yes

Severity/Certainty

Low/Low

lowlow.png
Full description

Variadic functions access their variable arguments by using va_start() to initialize an object of type va_list, iteratively invoking the va_arg() macro, and finally calling va_end(). The va_list may be passed as an argument to another function, but calling va_arg() within that function causes the va_list to have an indeterminate value in the calling function. As a result, attempting to read variable arguments without reinitializing the va_list can have unexpected behavior.

Coding standards
CERT MSC39-C

Do not call va_arg() on a va_list that has indeterminate value

Code examples

The following code example fails the check and will give a warning:

#include <stdarg.h>
#include <stdio.h>

int contains_zero(size_t count, va_list ap) {
  for (size_t i = 1; i < count; ++i) {
    if (va_arg(ap, double) == 0.0) {
      return 1;
    }
  }
  return 0;
}

int print_reciprocals(size_t count, ...) {
  va_list ap;
  va_start(ap, count);

  if (contains_zero(count, ap)) {
    va_end(ap);
    return 1;
  }

  for (size_t i = 0; i < count; ++i) {
    printf("%f ", 1.0 / va_arg(ap, double));
  }

  va_end(ap);
  return 0;
}

The following code example passes the check and will not give a warning about this issue:

#include <stdarg.h>
#include <stdio.h>

int contains_zero(size_t count, va_list *ap) {
  va_list ap1;
  va_copy(ap1, *ap);
  for (size_t i = 1; i < count; ++i) {
    if (va_arg(ap1, double) == 0.0) {
      return 1;
    }
  }
  va_end(ap1);
  return 0;
}

int print_reciprocals(size_t count, ...) {
  int status;
  va_list ap;
  va_start(ap, count);

  if (contains_zero(count, &ap)) {
    printf("0 in arguments!\n");
    status = 1;
  } else {
    for (size_t i = 0; i < count; i++) {
      printf("%f ", 1.0 / va_arg(ap, double));
    }
    printf("\n");
    status = 0;
  }

  va_end(ap);
  return status;
}