Main Content

MISRA C++:2023 Rule 25.5.3

The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function

Since R2024b

Description

Rule Definition

The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function.

Rationale

The C Standard allows nonreentrant functions such as getenv to return a pointer to a static buffer. Because the buffer is static, a second call to getenv can modify the buffer. If you continue to use the pointer returned from the first call past the second call, you can see unexpected results. The buffer that it points to might no longer contain values from the first call.

The same rationale is true for other nonreentrant functions covered by this rule. For the purposes of this rule, calls to these pairs of functions are treated as calls to the same function:

  • setlocale and localeconv

  • asctime and ctime

  • gmtime and localtime

Polyspace Implementation

Polyspace® reports violations of this rule when these events happen in this sequence:

  1. You point to the buffer returned from a nonreentrant standard function such as getenv or setlocale.

    user = getenv("USER");
  2. You call that nonreentrant standard function or its matching pair again.

    user2 = getenv("USER2");
  3. You use or dereference the pointer from the first step expecting the buffer to remain unmodified since that step. In the meantime, the call in the second step has modified the buffer.

    For instance:

    var=*user;

In some cases, a violation can appear when you do not call the getenv function a second time but simply return the pointer. For example:

char* func() {
     user=getenv("USER");
     .
     .
     return user;
}

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

In this example, the pointer user_name_from_home is derived from the pointer home. home points to the buffer returned from the first call to getenv. Therefore, user_name_from_home points to a location in the same buffer.

#include <cstdlib>
#include <cstring>

int func()
{
	int result = 0;

	char *home = getenv("HOME");   /* First call */
	if(home != NULL) {
		char *user = NULL;
		char *user_name_from_home = strrchr(home, '/');

		if(user_name_from_home != NULL) {
			user = getenv("USER");   /* Second call */
			if((user != NULL) &&
			        (strcmp(user, user_name_from_home) == 0)) // Noncompliant
			{
				result = 1;
			}
		}
	}
	return result;
}

After the second call to getenv, the buffer is modified. If you continue to use user_name_from_home, you can get unexpected results.

Correction — Make Copy of Buffer Before Second Call

If you want to access the buffer from the first call to getenv past the second call, make a copy of the buffer after the first call. One possible correction is to use the strdup function to make the copy.

#include <stdlib.h>
#include <string.h>

int func()
{
    int result = 0;

    char *home = getenv("HOME");    
    if (home != NULL) {
        char *user = NULL;
        char *user_name_from_home = strrchr(home, '/'); 
        if (user_name_from_home != NULL) {
            /* Make copy before second call */
            char *saved_user_name_from_home = strdup(user_name_from_home); 
            if (saved_user_name_from_home != NULL) {
                user = getenv("USER");  
                if ((user != NULL) &&
                    (strcmp(user, saved_user_name_from_home) == 0)) 
                {
                    result = 1;
                }
                free(saved_user_name_from_home);
            }
        }
    }
    return result;
}

Check Information

Group: Localization library
Category: Mandatory

Version History

Introduced in R2024b