Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: width->precision; reviewed

...

Code Block
bgColor#ccccff
langc
#include <stddef.h>
#include <assert.h>
#include <limits.h>
#include <inttypes.h>
 
extern size_t popcount(uintmax_t);
#define UWIDTHPRECISION(umax_value) popcount(umax_value) 
  
void func(signed int si_a, signed int si_b) {
  signed int result;
  signed long long tmp;
  assert(UWIDTHPRECISION(ULLONG_MAX) >=
         2 * UWIDTHPRECISION(UINT_MAX));
  tmp = (signed long long)si_a * (signed long long)si_b;
 
  /*
   * If the product cannot be represented as a 32-bit integer,
   * handle as an error condition.
   */
  if ((tmp > INT_MAX) || (tmp < INT_MIN)) {
    /* Handle error */
  } else {
    result = (int)tmp;
  }
  /* ... */
}

The assertion fails if long long has less than twice the width of int. The  UWIDTHPRECISION() macro and popcount() function are explained in INT35-C. Use correct integer precisions.  The following portable compliant solution can be used for on any conforming implementation, including those where this assertion fails:

...

The C Standard, 6.5.7 paragraph 4 [ISO/IEC 9899:2011], states

...

In almost every case, an attempt to shift by a negative number of bits or by more bits than exist in the operand indicates a bug (logic error). These issues are covered by INT34-C. Do not shift a negative number of bits or more bits than exist in the operand.

Noncompliant Code Example

This noncompliant code example can result in an unrepresentable value. 

Code Block
bgColor#FFcccc
langc
#include <limits.h>
#include <stddef.h>
#include <inttypes.h>
 
extern size_t popcount(uintmax_t);
#define UWIDTHPRECISION(umax_value) popcount(umax_value) 

void func(signed long si_a, signed long si_b) {
  signed long result;
  if ((si_a < 0) || (si_b < 0) ||
      (si_b >= UWIDTHPRECISION(ULONG_MAX)) {
    /* Handle error */
  } else {
    result = si_a << si_b;
  }
 
  /* ... */
}

Compliant Solution

This compliant solution eliminates the possibility of overflow resulting from a left-shift operation:

Code Block
bgColor#ccccff
langc
#include <limits.h>
#include <stddef.h>
#include <inttypes.h>
 
extern size_t popcount(uintmax_t);
#define UWIDTHPRECISION(umax_value) popcount(umax_value) 

void func(signed long si_a, signed long si_b) {
  signed long result;
  if ((si_a < 0) || (si_b < 0) ||
      (si_b >= UWIDTHPRECISION(ULONG_MAX)) ||
      (si_a > (LONG_MAX >> si_b))) {
    /* Handle error */
  } else {
    result = si_a << si_b;
  }
 
  /* ... */
}

The UWIDTHThe PRECISION() macro provides the correct width for an unsigned integer type (see INT19INT35-C. Correctly compute Use correct integer widthsprecisions)

 

Anchor
Unary Negation
Unary Negation

...