GitHub
CERT Secure Coding

STR30-C. Do not attempt to modify string literals

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 character. 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 any portion of a string literal. Modifying a string literal frequently results in an access violation because string literals are typically stored in read-only memory. (See undefined behavior 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 str is initialized to the address of a string literal. Attempting to modify the string literal is undefined behavior 32 :

Non-compliant code
char *str  = "string literal";
str[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 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 str . The string stored in str can be modified safely.

Compliant code
char str[] = "string literal";
str[0] = 'S';

Noncompliant Code Example (POSIX)

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

Non-compliant code
#include <stdlib.h>
 
void func(void) {
  mkstemp("/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 of passing a string literal:

Compliant code
#include <stdlib.h>
 
void func(void) {
  static char fname[] = "/tmp/edXXXXXX";
  mkstemp(fname);
}

Noncompliant Code Example (Result of strrchr() )

In this noncompliant example, the char * result of the strrchr() function is used to modify the object pointed to by pathname . Because the argument to strrchr() points to a string literal, the effects of the modification are undefined.

Non-compliant code
#include <stdio.h>
#include <string.h>
 
const char *get_dirname(const char *pathname) {
  char *slash;
  slash = strrchr(pathname, '/');
  if (slash) {
    *slash = '\0'; /* Undefined behavior */
  }
  return pathname;
}

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

Compliant Solution (Result of strrchr() )

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 to callers of get_dirname() , 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 * .

Compliant code
#include <stddef.h>
#include <stdio.h>
#include <string.h>
 
char *get_dirname(const char *pathname, char *dirname, 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, slash_idx);
      dirname[slash_idx] = '\0';      
      return dirname;
    }
  }
  return 0;
}
 
int main(void) {
  char dirname[260];
  if (get_dirname(__FILE__, dirname, sizeof(dirname))) {
    puts(dirname);
  }
  return 0;
}

Risk Assessment

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

Rule Severity Likelihood Detectable Repairable Priority Level
STR30-C Low Likely No Yes P6 L2

Automated Detection

Tool

Version

Checker

Description

Astrée
25.10
string-literal-modfication
write-to-string-literal
Fully checked
Axivion Bauhaus Suite

7.2.0

CertC-STR30Fully implemented
Compass/ROSE

Can detect simple violations of this rule

Coverity
2017.07
PWDeprecates conversion from a string literal to "char *"
Cppcheck Premium

24.11.0

premium-cert-str30-c
Helix QAC

2025.2

C0556, C0752, C0753, C0754

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


Klocwork

2025.2

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


LDRA tool suite
9.7.1

157 S

Partially implemented
Parasoft C/C++test
2025.2

CERT_C-STR30-a
CERT_C-STR30-b

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

PC-lint Plus

1.4

489, 1776

Partially supported

Polyspace Bug Finder

R2025b

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


PVS-Studio

7.42

V675
RuleChecker

25.10

string-literal-modficationPartially checked
Splint

3.1.1



TrustInSoft Analyzer

1.38

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

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 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

[ ISO/IEC 9899:2024 ]6.4.5, "String Literals"
[ Plum 1991 ]Topic 1.26, "Strings—String Literals"
[ Summit 1995 ]comp.lang.c FAQ List, Question 1.32