Main Content

CERT C++: ENV34-C

Do not store pointers returned by certain functions

Description

Rule Definition

Do not store pointers returned by certain functions.1

Polyspace Implementation

The rule checker checks for Misuse of return value from nonreentrant standard function.

Examples

expand all

Issue

Misuse of return value from nonreentrant standard function occurs 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 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, the defect might appear even if you do not call the getenv function a second time but simply return the pointer. For instance:

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

For information on which functions are covered by this defect, see documentation on nonreentrant standard functions.

Risk

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 modifies 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 no longer has values from the first call.

The defect appears even if you do not call getenv a second time but simply return the pointer. The reason is that someone calling your function might use the returned pointer after a second call to getenv. By returning the pointer from your call to getenv, you make your function unsafe to use.

The same rationale is true for other nonreentrant functions covered by this defect.

Fix

After the first call to getenv, make a copy of the buffer that the returned pointer points to. After the second call to getenv, use this copy. Even if the second call modifies the buffer, your copy is untouched.

Example - Return from getenv Used After Second Call to getenv
#include <stdlib.h>
#include <string.h>

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

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.

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: 49. Miscellaneous (MSC)

Version History

Introduced in R2019a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.