Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Updated UB references from C11->C23

According to the C Standard, 6.4.5, paragraph 3 [ISO/IEC 9899:2024]:

A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes

...

, as in "xyz"

...

. A UTF-8 string literal is the same, except prefixed by u8. A wchar_t string literal is the same, except prefixed by L. A UTF-16 string literal is the same, except prefixed by

...

u. A UTF-32 string literal is the same, except prefixed by U. Collectively, wchar_t, UTF-16, and UTF-32 string literals are called wide string literals.

At compile time, string literals are used to create an array of static storage duration of sufficient length to contain the character sequence and a terminating null -termination charactercharacter. String literals are usually referred to by a pointer to (or array of) characters. Ideally, they should be assigned only to pointers to (or arrays of) const char or const wchar_t. It is unspecified whether these arrays of string literals are distinct from each other. The behavior is undefined if a program attempts to modify string literals but any portion of a string literal. Modifying a string literal frequently results in an access violation , as because string literals are typically stored in read-only memory. (See also undefined behavior 30 of Annex J of C99.

Do not attempt to modify a string literal. Use a named array of characters to obtain a modifiable string.

32.)

Avoid assigning a string literal to a pointer to non-const or casting a string literal to a pointer to non-const. For the purposes of this rule, a pointer to (or array of) const characters must be treated as a string literal. Similarly, the returned value of the following library functions must be treated as a string literal if the first argument is a string literal:

  • strpbrk(), strchr(), strrchr(), strstr()
  • wcspbrk(), wcschr(), wcsrchr(), wcsstr()
  • memchr(), wmemchr()

This rule is a specific instance of EXP40-C. Do not modify constant objects.

Noncompliant Code Example

In this noncompliant code example, the char pointer p is str is initialized to the address of a string literal. Attempting to modify the string literal results in is undefined behavior.:

Code Block
bgColor#FFcccc
langc

char *pstr  = "string literal";
pstr[0] = 'S';

Compliant Solution

As an array initializer, a string literal specifies the initial values of characters in an array as well as the size of the array. (see STR36See STR11-C. Do not specify the bound of a character array initialized with a string literal.) . This code creates a copy of the string literal in the space allocated to the character array a str. The string stored in a can str can be modified safely modified.

Code Block
bgColor#ccccff
langc

char astr[] = "string literal";
astr[0] = 'S';

Noncompliant Code Example (POSIX)

In this noncompliant code example, a string literal is passed to the mktemp (pointer to non-const) parameter of the POSIX function modifies its string argument. mkstemp(), which then modifies the characters of the string literal:

Code Block
bgColor#FFcccc
langc
#include <stdlib.h>
 
void func(void) {
  mkstemp
char *fname;
fname = mktemp("/tmp/edXXXXXX");
}

The behavior of mkstemp() is described in more detail in FIO21-C. Do not create temporary files in shared directories.

Compliant Solution

...

(POSIX)

This compliant solution uses a named array instead Instead of passing a string literal, use a named array:

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
 
void func(void) {
  static char fname[] = "/tmp/edXXXXXX";
mktemp  mkstemp(fname);
}

Noncompliant Code Example (Result of strrchr())

In this noncompliant example, the non-const char * result of the strchrstrrchr() function is used to modify the object pointed to by pathname. Since the pointer  Because the argument to strrchr() points to a string literal, the effects of the modification are undefined and are likely to cause a signal such as SIGSEGV to be generated for the process if the object is stored in read-only memory.

Code Block
bgColor#FFcccc
langc
#include <stdio.h>
#include <string.h>
 
const char * get_dirname(const char * pathname) {
  char * slash;
  slash = strrchr(pathname, '/');
  if (slash) {
    *slash = '\0'; /* undefinedUndefined behavior */
  }
  return pathname;
}

int main(void) {
  puts(get_dirname(__FILE__));
  return 0;
}

Compliant Solution (Result of strrchr())

A compliant This compliant solution avoids modifying a const object, even if it is possible to obtain a non-const pointer to such an object by calling a standard C library function, such as strrchr(). To reduce the risk of to callers of get_dirname() passing constant objects to the function the argument is declared to be a non-const pointer. While converting a string literal to non-const char* is permitted by the language conforming compilers may issue a diagnostic for such code. See also EXP05-C. Do not cast away a const qualification, a buffer and length for the directory name are passed into the function. It is insufficient to change pathname to require a char * instead of a const char * because conforming compilers are not required to diagnose passing a string literal to a function accepting a char *.

Code Block
bgColor#ccccff
langc
#include <stddef.h>
#include <stdio.h>
#include <string.h>
 
char * get_dirname(const char *pathname, char * pathnamedirname, size_t size) {
  const char * slash;
   slash = strrchr(pathname, '/');
  if (slash) {
    ptrdiff_t slash_idx = slash - pathname;
    if ((size_t)slash_idx < size) {
      memcpy(dirname, pathname,  *slashslash_idx);
      dirname[slash_idx] = '\0';      
      return pathnamedirname;
    }
  }
  return 0;
}
 
int main(void) {
   char pathnamedirname[] = __FILE__260];
  if /* calling (get_dirname(__FILE__), may be diagnosed */
 dirname, sizeof(dirname))) {
    puts(get_dirname(pathname));
  }
  return 0;
}

Risk Assessment

Modifying string literals can lead to abnormal program termination and possibly denial-of-service attacks.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

STR30-C

low

Low

likely

Likely

low

Low

P9

L2

Automated Detection

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

Splint Version 3.1.1 can detect violations of this rule.

...


Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V
string-literal-modfication
write-to-string-literal
Fully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-STR30Fully implemented
Compass/ROSE

Can detect simple violations of this rule

Coverity
Include Page
Coverity_V
Coverity_V
PWDeprecates conversion from a string literal to "char *"
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C0556, C0752, C0753, C0754

C++3063, C++3064, C++3605, C++3606, C++3607


Klocwork

Include Page
Klocwork_V
Klocwork_V

CERT.STR.ARG.CONST_TO_NONCONST
CERT.STR.ASSIGN.CONST_TO_NONCONST


LDRA tool suite
Include Page
LDRA_V
LDRA_V

157 S

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

CERT_C-STR30-a
CERT_C-STR30-b

A string literal shall not be modified
Do not modify string literals

PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

489, 1776

Partially supported

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule STR30-CChecks for writing to const qualified object (rule fully covered)


PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V675
RuleChecker

Include Page
RuleChecker_V
RuleChecker_V

string-literal-modficationPartially checked
Splint

Include Page
Splint_V
Splint_V



TrustInSoft Analyzer

Include Page
TrustInSoft Analyzer_V
TrustInSoft Analyzer_V

mem_accessExhaustively verified (see one compliant and one non-compliant example).

Related Vulnerabilities

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

Other Languages

This rule appears in the C++ Secure Coding Standard as STR30-CPP. Do not attempt to modify string literals.

References

...

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT C Secure Coding StandardEXP05-C. Do not cast away a const qualificationPrior to 2018-01-12: CERT: Unspecified Relationship
CERT C Secure Coding StandardSTR11-C. Do not specify the bound of a character array initialized with a string literalPrior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TS 17961:2013Modifying string literals [strmod]Prior to 2018-01-12: CERT: Unspecified Relationship

Bibliography

...

6.4.5,

...

"String

...

Literals"

...

[Plum 1991]Topic 1.26, "Strings—String Literals"
[Summit 1995]comp.lang.c FAQ List, Question 1.32


...

Image Added Image Added FAQ list - Question 1.32 \[[Plum 91|AA. References#Plum 91]\] Topic 1.26, "strings - string literals"Image Removed      07. Characters and Strings (STR)      Image Modified