Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Signed character data must be converted to an unsigned type char before being assigned or converted to a larger signed type. Because compilers have the latitude to define char This rule applies to both signed char and (plain) char characters on implementations where char is defined to have the same range, representation, and behavior behaviors as either signed char or unsigned char.

However, this rule should be applied to both signed char and (plain) char characters.This rule is only applicable in only in cases where the character data may contain values that can be interpreted as negative valuesnumbers. For example, if the char type is represented by a two's complement 8-bit value, any character value greater than +127 is interpreted as a negative value.

This rule is a generalization of STR37-C. Arguments to character-handling functions must be representable as an unsigned char.

Noncompliant Code Example

This noncompliant code example is taken from a vulnerability in bash versions 1.14.6 and earlier that resulted in the that led to the release of CERT Advisory CA-1996-22. This vulnerability resulted from the sign extension of character data referenced by the string c_str pointer in the yy_string_get() function in the parse.y module of the bash source code:

Code Block
bgColor#FFcccc
langc

static int yy_string_get(void) {
  register char *stringc_str;
  register int c;

  stringc_str = bash_input.location.string;
  c = EOF;

  /* If the string doesn't exist, or is empty, EOF found. */
  if (stringc_str && *stringc_str) {
    c = *stringc_str++;
    bash_input.location.string = stringc_str;
  }
  return (c);
}

The string c_str variable is used to traverse the character string containing the command line to be parsed. As characters are retrieved from this pointer, they are stored in a variable of type int. For compilers implementations in which the char type defaults to is defined to have the same range, representation, and behavior as signed char, this value is sign-extended when assigned to the int variable. For character code 255 decimal (-1 −1 in two's complement form), this sign extension results in the value -1 −1 being assigned to the integer, which is indistinguishable from EOF.

Noncompliant Code Example

This problem was can be repaired by explicitly declaring the string c_str variable as unsigned char.:

Code Block
bgColor#FFcccc
langc

static int yy_string_get(void) {
  register unsigned char *stringc_str;
  register int c;

  stringc_str = bash_input.location.string;
  c = EOF;

  /* If the string doesn't exist, or is empty, EOF found. */
  if (stringc_str && *stringc_str) {
    c = *stringc_str++;
    bash_input.location.string = stringc_str;
  }
  return (c);
}

This solutionexample, however, is in violation of violates STR04-C. Use plain char for characters in the basic character set.

Compliant Solution

In this compliant solution, the result of the expression *stringc_str++ is cast to (unsigned char) before assignment to the int variable c.:

Code Block
bgColor#ccccff
langc

static int yy_string_get(void) {
  register char *stringc_str;
  register int c;

  stringc_str = bash_input.location.string;
  c = EOF;

  /* If the string doesn't exist, or is empty, EOF found. */
  if (stringc_str && *stringc_str) {
    /* castCast to unsigned type */
    c = (unsigned char)*stringc_str++;

    bash_input.location.string = string; = c_str;
  }
  return (c);
}

Noncompliant Code Example

In this noncompliant code example, the cast of *s to unsigned int can result in a value in excess of UCHAR_MAX because of integer promotions, a violation of ARR30-C. Do not form or use out-of-bounds pointers or array subscripts:

Code Block
bgColor#ffcccc
langc
#include <limits.h>
#include <stddef.h>
 
static const char table[UCHAR_MAX + 1] = { 'a' /* ... */ };

ptrdiff_t first_not_in_table(const char *c_str) {
  for (const char *s = c_str; *s; ++s) {
    if (table[(unsigned int)*s] != *s) {
      return s - c_str;
    }
  }
  return -1;
}

Compliant Solution

This compliant solution casts the value of type char to unsigned char before the implicit promotion to a larger type:

Code Block
bgColor#ccccff
langc
#include <limits.h>
#include <stddef.h>
 
static const char table[UCHAR_MAX + 1] = { 'a' /* ... */ };

ptrdiff_t first_not_in_table(const char *c_str) {
  for (const char *s = c_str; *s; ++s) {
    if (table[(unsigned char)*s] != *s) {
      return s - c_str;
    }
  }
  return -1;
}

Risk Assessment

This is a subtle error that results Conversion of character data resulting in a value in excess of UCHAR_MAX is an often-missed error that can result in a disturbingly broad range of potentially severe vulnerabilities.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

STR34-C

medium

Medium

probable

Probable

medium

Medium

P8

L2

Automated Detection

...

The LDRA tool suite V 7.6.0 can detect violations of this rule.

Fortify SCA Version 5.0 with CERT C Rule Pack can detect violations of this rule.

...

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V
char-sign-conversionFully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-STR34Fully implemented
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
MISC.NEGCHARNegative Character Value
Compass/ROSE

Can detect violations of this rule when checking for violations of INT07-C. Use only explicitly signed or unsigned char type for numeric values

Coverity
Include Page
Coverity_V
Coverity_V

MISRA C 2012 Rule 10.1

MISRA C 2012 Rule 10.2

MISRA C 2012 Rule 10.3

MISRA C 2012 Rule 10.4

Implemented

Essential type checkers

ECLAIR

Include Page
ECLAIR_V
ECLAIR_V

CC2.STR34

Fully implemented
GCC

2.95 and later

-Wchar-subscripts

Detects objects of type char used as array indices

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C2140, C2141, C2143, C2144, C2145, C2147, C2148, C2149, C2151, C2152, C2153, C2155

C++3051


Klocwork
Include Page
Klocwork_V
Klocwork_V
CXX.CAST.SIGNED_CHAR_TO_INTEGER


LDRA tool suite
Include Page
LDRA_V
LDRA_V

434 S

Partially implemented
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-STR34-b
CERT_C-STR34-c
CERT_C-STR34-d

Cast characters to unsigned char before assignment to larger integer sizes
An expressions of the 'signed char' type should not be used as an array index
Cast characters to unsigned char before converting to larger integer sizes

PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

571

Partially supported

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule STR34-CChecks for misuse of sign-extended character value (rule fully covered)
RuleChecker

Include Page
RuleChecker_V
RuleChecker_V

char-sign-conversionFully checked
TrustInSoft Analyzer

Include Page
TrustInSoft Analyzer_V
TrustInSoft Analyzer_V

out of bounds readPartially verified (exhaustively detects undefined behavior).

Related Vulnerabilities

CVE-2009-0887 results from a violation of this rule. In Linux PAM (up to version 1.0.3), the libpam implementation of strtok() casts a (potentially signed) character to an integer for use as an index to an array. An attacker can exploit this vulnerability by inputting a string with non-ASCII characters, causing the cast to result in a negative index and accessing memory outside of the array [xorl 2009].

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Other Languages

...

Related Guidelines

...

...

...

...

Arguments to character-handling functions must be representable as an unsigned char
STR04-C. Use plain char for characters in the basic character set
ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
ISO/IEC TS 17961:2013Conversion of signed characters to wider integer types before a check for EOF [signconv]
MISRA-C:2012

Rule 10.1 (required)

Rule 10.2 (required)

Rule 10.3 (required)

Rule 10.4 (required)

MITRE CWECWE-704, Incorrect Type Conversion or Cast

Bibliography


...

Image Added Image Added Image Added

References

Wiki Markup
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.2.5, "Types"
\[[MISRA 04|AA. C References#MISRA 04]\] Rule 6.1, "The plain char type shall be used only for the storage and use of character values."
\[[MITRE 07|AA. C References#MITRE 07]\] [CWE ID 704|http://cwe.mitre.org/data/definitions/704.html], "Incorrect Type Conversion or Cast"

STR33-C. Size wide character strings correctly      07. Characters and Strings (STR)      STR35-C. Do not copy data from an unbounded source to a fixed-length array