Realloc problem, environment variables Linux C



  • Hey Community,
    I have to write my own implementation of setenv, getenv and unsetenv on a linux system for school.

    Now if i'm adding an environment variable i have to copy all variables from stack to heap.
    That works fine. But if i'm adding more variables to the list realloc throws some strange error.
    I'm pretty shure the error occurs when realloc has to actually move the memory block. In most cases the error doesnt occure when calling realloc the first time

    Here's my whole implementation. If you dont want to read all the code, just look at env.c on the bottom in the function enter_env (CASE3)

    Env.h
    
    #ifndef ENV_H
    #define ENV_H
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    void init_env();
    void print_menu();
    void print_env();
    void print_specific_env( char *name);
    void delete_env(char*name);
    void enter_env(char* name, char* value);
    
    #endif
    
    Env.c
    
    #include "env.h"
    extern char ** environ; //Environment pointer
    char ** environ_intern; //Internal envitonment pointer
    int is_on_stack = 1;    //Environment on stack or heap?
    
    static void check_alloc(void*ptr)///checks if memory has been allocated correctly
    {
        if (ptr) {return;}                          //check for bad alloc
        perror("Not enough memory.");               //throw error
        exit(EXIT_FAILURE);
    }
    
    static char* make_env(char*name,char*value)///creates a new environment variable and returns its pointer
    {
        char *new_env = (char*) malloc ((strlen(name)+strlen(value) +1)*sizeof(char));//create variable
        check_alloc(new_env);    //check if correctly allocated
        strcpy(new_env,name);
        strcat(new_env, "=");
        strcat(new_env,value);
        return new_env;
    }
    
    static int get_environment_index(char** env, char* name)///returns index of environment variable ,returns -1 if not found
    {
        char temp = (char) malloc (strlen(name)+1)*sizeof(char);
        strcpy(temp, name);
        strcat(temp, "=");
        int i;
        for (i=0; env[i] != NULL;i++)
        {
            if (strstr(env[i],temp)){free(temp);return i; }//String found
        }
        free(temp);return -1; //not found
    }
    
    static int get_environment_length(char** env)///returns the length of the environment list
    {
        int i =0;
        while (env[i]!=NULL){i++;}
        return i;
    }
    
    void print_menu()///Prints the Environment Menu
    {
        printf("-----------------------\n");
        printf ("Environment-List\n");
        printf("-----------------------\n");
        printf("\n\n0: End\n");
        printf("1: Show environment list\n");
        printf("2: Read single variable\n");
        printf("3: Add new variable\n");
        printf("4: Delete Variable \n");
        printf("\n\nYour choice:");
    }
    
    void init_env()///Set pointer to internal environment variable
    {
        environ_intern = environ;
    }
    
    void print_env()///Print all environment variables
    {
        int i;
        for (i=0; environ_intern[i] != NULL;i++){printf("%d,%s\n", i,environ_intern[i]);}
    }
    
    void print_specific_env(char *name)///Print a specific environment variable
    {
        int i = get_environment_index( environ_intern, name); //get index
        if ( i!=-1){printf("%s\n", environ_intern[i]);}    //print if found
    }
    
    void delete_env(char*name)///Delete an environment variable -- we have to shift all variables above the index one item up
    {
        int j = get_environment_index(environ_intern, name),i =j; //i an j get position of index
        if (i == -1){return;}    //environment variable doesnt exist
        do{environ_intern[j] = environ_intern[j+1];j++;}while( environ[j+1] != NULL);//shift up
      //  if(!is_on_stack){free(environ[j+1]);environ[j+1] = NULL;} //free memory if necessary
    }
    
    void enter_env(char* name, char* value)/// Adds an environment variable
    {
        int i = get_environment_index(environ_intern, name);    //check if exists
    
        if (i!=-1) // CASE 1 Already existing -- Simply create a new variable and replace
        {
            environ_intern[i] = make_env(name,value);//create the new variable and overwrite the old
            return;
        }
        int env_size = get_environment_length(environ_intern);//Get number of environment variables
        if (is_on_stack) // CASE 2 First time Copy everything to Heap
        {
            environ_intern = (char**) malloc ((env_size+1)*sizeof(char*)); //allocate new environment list
            check_alloc(environ_intern);                                    //check if memory has been allocated
            for (i=0; i < env_size;i++)//copy environment variables from stack to heap (DEEP COPY)
            {
                char *new_env = (char*) malloc (sizeof(environ[i])*sizeof(char)+1);
                strcpy(new_env,environ[i]);
                environ_intern[i] = new_env;
            }
            environ_intern[i] = make_env(name,value);                       //create the new variable
            environ_intern[i+1]= NULL;                                      //end with zero
            environ = environ_intern;                                       //refering environment variable to new adress
            is_on_stack = 0;                                                //now everything is on heap
            return;
        }
        // CASE 3 Already on HEAP, reallocate space
        environ_intern = realloc (environ_intern,(env_size+1)*sizeof(char*));           //get length of environment
        check_alloc(environ_intern); //check if memory has been allocated correctly
        environ_intern[env_size] = make_env(name,value);                           //create the new variable
        environ_intern[env_size+1]= NULL; //terminate end with zero
        environ = environ_intern; //In case realloc moved memory around the environ pointer would become dangling
    }
    
    Main.c
    
    #include <stdio.h>
    #include "env.h"
    #define BUFSIZE 256
    #define FLUSH_INP while ( getchar() != '\n'); ///Emptys the Input Buffer
    
    int main (int argc, char*argv[])
    {
        init_env();
        while (1)
        {
            char param1[BUFSIZE],param2[BUFSIZE];
            print_menu();
    
            switch (getchar())
            {
            case '0': ///EXIT
                exit(EXIT_SUCCESS);
            case '1': ///PRINT ALL
                print_env();
                break;
            case '2': ///PRINZ SPEVIFIC
                printf("Name of variable:");
                scanf("%s", param1);
                print_specific_env(param1);
                break;
            case '3':///SET_ENV
                printf("enter name:");
                scanf("%s", param1);
                FLUSH_INP;
                printf("enter value:");
                scanf("%s", param2);
                enter_env(param1,param2);
                break;
            case '4':///DELETE ENV
                printf("Name of variable:");
                scanf("%s", param1);
                delete_env(param1);
                break;
            default :
                printf("unknown command\n");
            }
            FLUSH_INP
        }
    }
    

    Error Message

    ** glibc detected *** ./directory: realloc(): invalid next size: 0x0000000001aca010 ***
    ======= Backtrace: =========
    /lib/libc.so.6(+0x775b6)[0x7f1b05bbc5b6]
    /lib/libc.so.6(+0x7dd96)[0x7f1b05bc2d96]
    /lib/libc.so.6(realloc+0xf0)[0x7f1b05bc30b0]
    ./directory[0x400ed4]
    ./directory[0x40107e]
    /lib/libc.so.6(__libc_start_main+0xfd)[0x7f1b05b63c4d]
    ./directory[0x400909]
    ======= Memory map: ========
    00400000-00402000 r-xp 00000000 08:01 524295 /home/gunther/Desktop/bes/directory
    00601000-00602000 r--p 00001000 08:01 524295 /home/gunther/Desktop/bes/directory
    00602000-00603000 rw-p 00002000 08:01 524295 /home/gunther/Desktop/bes/directory
    01aca000-01aeb000 rw-p 00000000 00:00 0 [heap]
    7f1b00000000-7f1b00021000 rw-p 00000000 00:00 0
    7f1b00021000-7f1b04000000 ---p 00000000 00:00 0
    7f1b0592e000-7f1b05944000 r-xp 00000000 08:01 24043880 /lib/libgcc_s.so.1
    7f1b05944000-7f1b05b43000 ---p 00016000 08:01 24043880 /lib/libgcc_s.so.1
    7f1b05b43000-7f1b05b44000 r--p 00015000 08:01 24043880 /lib/libgcc_s.so.1
    7f1b05b44000-7f1b05b45000 rw-p 00016000 08:01 24043880 /lib/libgcc_s.so.1
    7f1b05b45000-7f1b05cbf000 r-xp 00000000 08:01 24043728 /lib/libc-2.11.1.so
    7f1b05cbf000-7f1b05ebe000 ---p 0017a000 08:01 24043728 /lib/libc-2.11.1.so
    7f1b05ebe000-7f1b05ec2000 r--p 00179000 08:01 24043728 /lib/libc-2.11.1.so
    7f1b05ec2000-7f1b05ec3000 rw-p 0017d000 08:01 24043728 /lib/libc-2.11.1.so
    7f1b05ec3000-7f1b05ec8000 rw-p 00000000 00:00 0
    7f1b05ec8000-7f1b05ee8000 r-xp 00000000 08:01 24043631 /lib/ld-2.11.1.so
    7f1b060c2000-7f1b060c5000 rw-p 00000000 00:00 0
    7f1b060e3000-7f1b060e7000 rw-p 00000000 00:00 0
    7f1b060e7000-7f1b060e8000 r--p 0001f000 08:01 24043631 /lib/ld-2.11.1.so
    7f1b060e8000-7f1b060e9000 rw-p 00020000 08:01 24043631 /lib/ld-2.11.1.so
    7f1b060e9000-7f1b060ea000 rw-p 00000000 00:00 0
    7fffa1830000-7fffa1845000 rw-p 00000000 00:00 0 [stack]
    7fffa1955000-7fffa1956000 r-xp 00000000 00:00 0 [vdso]
    ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

    Aborted

    Thanks for any hints in advance.
    Greets yodakohl



  • dont worry about get_environment_index. I know it's wrong 😃 I have mistakenly posted the developement version. This is the original one

    static int get_environment_index(char** env, char* name)///returns index of environment variable ,returns -1 if not found
    {
        char temp[256];
        strcpy(temp, name);
        strcat(temp, "=");
        int i;
        for (i=0; env[i] != NULL;i++)
        {
            if (strstr(env[i],temp)){return i; }//String found
        }
        return -1; //not found
    }
    


  • No offense, but nobody's going to read through this whole mess. (No, telling people to only read a specific section of your code won't help much.)

    If you want help, you should really try find a minimal working example (or rather minimal error example) and post it here, otherwise nobody's going to bother reading your source code.



  • Btw, crossposting is generally frowned upon. Thread closed.


Anmelden zum Antworten