Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fairly large edits; reviewed

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

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 wide string literal is the same, except prefixed by the letter

...

L, u, or U.

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 null-termination character. It is unspecified whether these arrays are distinct. The behavior is undefined if a program attempts to modify string literals but frequently results in an access violation because string literals are typically stored in read-only memory. See also undefined behavior 33  of Annex J of the C Standard [ISO/IEC 9899:2011].The returned value of the library functions .

String literals are usually referred to via a pointer to, or array of, const characters.

When called with a pointer to (or array of) const characters, the return value from the following functions shall be treated as a pointer to const characters:

  • strpbrk(), strchr(), strrchr(), strstr()
  • wcspbrk(), wcschr(),

...

  •  wcsrchr(), wcsstr()
  • memchr(), wmemchr()

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

...

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

}

Compliant Solution (POSIX)

...

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

}

Noncompliant Code Example (Result of strrchr())

In this noncompliant example, the non-const char * result of the strrchr() function is used to modify the object pointed to by pathname. Because the pointer 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'; /* Undefined behavior */
  }
  return pathname;
}

int main() {
  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 callers of get_dirname() passing constant objects to the function, the argument is declared to be a non-const pointer. Although converting a string literal to non-const char* is permitted by the language, conforming compilers could 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 <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,  *slashslash_idx);
      dirname[slash_idx] = '\0';      
      return dirname;
    }
  }
  return pathname0;
}
 
int main() {
   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.

...

Bibliography

[ISO/IEC 9899:2011]6.4.5, "String literals"
Annex J, subclause J.2, "Undefined Behavior" 
[Plum 1991]Topic 1.26, "Strings—String Literals"
[Summit 1995]comp.lang.c FAQ list, Question 1.32

 

...