GitHub
CERT Secure Coding

STR37-C. Arguments to character-handling functions must be representable as an unsigned char

According to the C Standard, 7.4.1 paragraph 1 [ ISO/IEC 9899:2024 ],

The header <ctype.h> declares several functions useful for classifying and mapping characters. In all cases the argument is an int , the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF . If the argument has any other value, the behavior is undefined .

See also undefined behavior 112 .

This rule is applicable only to code that runs on platforms where the char data type is defined to have the same range, representation, and behavior as signed char .

Following are the character classification functions that this rule addresses:

isalnum()isalpha()isascii() XSIisblank()
iscntrl()isdigit()isgraph()islower()
isprint()ispunct()isspace()isupper()
isxdigit()toascii() XSItoupper()tolower()

XSI denotes an X/Open System Interfaces Extension to ISO/IEC 9945—POSIX. These functions are not defined by the C Standard.

This rule is a specific instance of STR34-C. Cast characters to unsigned char before converting to larger integer sizes .

Noncompliant Code Example

On implementations where plain char is signed, this code example is noncompliant because the parameter to isspace() , *t , is defined as a const char * , and this value might not be representable as an unsigned char :

Non-compliant code
#include <ctype.h>
#include <string.h>
 
size_t count_preceding_whitespace(const char *s) {
  const char *t = s;
  size_t length = strlen(s) + 1;
  while (isspace(*t) && (t - s < length)) { 
    ++t;
  }
  return t - s;
}

The argument to isspace() must be EOF or representable as an unsigned char ; otherwise, the result is undefined.

Compliant Solution

This compliant solution casts the character to unsigned char before passing it as an argument to the isspace() function:

Compliant code
#include <ctype.h>
#include <string.h>
 
size_t count_preceding_whitespace(const char *s) {
  const char *t = s;
  size_t length = strlen(s) + 1;
  while (isspace((unsigned char)*t) && (t - s < length)) { 
    ++t;
  }
  return t - s;
}

Risk Assessment

Passing values to character handling functions that cannot be represented as an unsigned char to character handling functions is undefined behavior 112 .

Rule Severity Likelihood Detectable Repairable Priority Level
STR37-C Low Unlikely Yes Yes P3 L3

Automated Detection

Tool

Version

Checker

Description

Astrée
25.10
ctype-limitsPartially checked
Axivion Bauhaus Suite

7.2.0

CertC-STR37Fully implemented
CodeSonar
9.1p0
MISC.NEGCHARNegative character value
Compass/ROSE

Could detect violations of this rule by seeing if the argument to a character handling function (listed above) is not an unsigned char

ECLAIR

1.2

CC2.STR37

Fully implemented

Helix QAC

2025.2

C4413, C4414

C++3051

DF2796, DF2797, DF2798, DF2799


Klocwork
2025.2
AUTOSAR.STDLIB.CCTYPE.UCHAR
MISRA.ETYPE.ASSIGN.2012


LDRA tool suite
9.7.1
663 SFully implemented
Parasoft C/C++test

2025.2

CERT_C-STR37-aDo not pass incorrect values to ctype.h library functions
Polyspace Bug Finder

R2025b

CERT C: Rule STR37-C

Checks for invalid use of standard library integer routine (rule fully covered)

RuleChecker

25.10

ctype-limitsPartially checked
Security Reviewer - Static Reviewer

6.02

UNSAFE_01Fully implemented
TrustInSoft Analyzer

1.38

valid_charPartially verified.

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

Key here (explains table format and definitions)

TaxonomyTaxonomy itemRelationship
CERT C Secure Coding StandardSTR34-C. Cast characters to unsigned char before converting to larger integer sizesPrior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TS 17961Passing arguments to character-handling functions that are not representable as unsigned char [chrsgnext]Prior to 2018-01-12: CERT: Unspecified Relationship
CWE 2.11CWE-704 , Incorrect Type Conversion or Cast2017-06-14: CERT: Rule subset of CWE

CERT-CWE Mapping Notes

Key here for mapping notes

CWE-686 and STR37-C

Intersection( CWE-686, STR37-C) = Ø

STR37-C is not about the type of the argument passed (which is signed int), but about the restrictions placed on the value in this type (must be 0-UCHAR_MAX or EOF). I interpret ‘argument type’ to be specific to the C language, so CWE-686 does not apply to incorrect argument values, just incorrect types (which is relatively rare in C, but still possible).

CWE-704 and STR37-C

STR37-C = Subset( STR34-C)

CWE-683 and STR37-C

Intersection( CWE-683, STR37-C) = Ø

STR37-C excludes mis-ordered function arguments (assuming they pass type-checking), because there is no easy way to reliably detect violations of CWE-683.

Bibliography

[ ISO/IEC 9899:2024 ]7.4.1, "Character Handling < ctype.h >"
[ Kettlewell 2002 ]Section 1.1, "< ctype.h > and Characters Types"