Home > Net >  Heap buffer overflow caused by single line
Heap buffer overflow caused by single line

Time:07-06

Currently trying to work on my C (very new to it) by doing some leetcode questions. I'm puzzled by this issue, as it gives me a heap buffer overflow but only because of a single line. interpret() is called and passed a string command where 1 <= command.length <= 100, and will consist of "G", "()", and/or "(al)" in some order, with no other characters appearing.

char * interpret(char * command){
    
    char * ret = malloc(sizeof(char) * 100);
    int counter = 0;
    for(int i = 0; i < sizeof(command) - 1; i  )
    {
        if(command[i] == 'G')
        {
            ret[counter] = 'G';
            counter   ;
        }
        else if(command[i] == '(')
        {
            if (command[i   1] == ')')
            {
                ret[counter] = 'o';
                counter   ;
            }
            else
            {
                //ret[counter] = 'a'; ***********
                ret[counter   1] = 'l';
                counter  = 2;
            }
        }
        ret[counter] = '\0';
    }
    return realloc(ret, counter * sizeof(char));
}

If the starred line is uncommented, then the entire program crashes in leetcode, but works fine on VSCode and returns the correct solution. I would appreciate any help, I'm sure it's something small I'm missing. Thanks.

ETA: Here is the leetcode problem in question

CodePudding user response:

The parameter command has the pointer type char *.

So the operator sizeof applied to the pointer yields the size of the pointer instead of the length of the pointed string

for(int i = 0; i < sizeof(command) - 1; i  )

You could just write

for( size_t i = 0; command[i] != '\0'; i  )

Also it is unclear why there is used the magic number 100

char * ret = malloc(sizeof(char) * 100);

You could at first count the result characters and then allocated an array of the appropriate size and fill it.

Moreover due to this statement

    ret[counter] = '\0';

(that is also unclear why it is within the for loop) you need to allocate an array with counter 1 characters instead of counter characters as you are doing

return realloc(ret, counter * sizeof(char));

A straightforward approach can look the following way as shown in the demonstration program below.

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

char * interpret( const char *command )
{
    size_t n = 0;

    for ( size_t i = 0; command[i] != '\0';  )
    {
        if ( command[i] == 'G' )
        {
              n;
              i;
        }
        else if ( strncmp( command   i, "()", 2 ) == 0 )
        {
              n;
            i  = 2;
        }
        else if (  strncmp( command   i, "(al)", 4 ) == 0 )
        {
            n  = 2;
            i  = 4;
        }
        else
        {
              i;
        }
    }

    char *result = malloc( n   1 );

    if ( result != NULL )
    {
        n = 0;

        for ( size_t i = 0; command[i] != '\0';  )
        {
            if ( command[i] == 'G' )
            {
                result[n  ] = 'G';
                  i;
            }
            else if ( strncmp( command   i, "()", 2 ) == 0 )
            {
                result[n  ] = 'o';
                i  = 2;
            }
            else if (  strncmp( command   i, "(al)", 4 ) == 0 )
            {
                result[n  ] = 'a';
                result[n  ] = 'l';
                i  = 4;
            }
            else
            {
                  i;
            }
        }

        result[n] = '\0';
    }

    return result;
}

int main( void )
{
    char *s = interpret( "G()(al)" );
    if ( s ) puts( s );
    free( s );

    s = interpret( "(al)G(al)()()G" );
    if ( s ) puts( s );
    free( s );
}

The program output is

Goal
alGalooG

CodePudding user response:

Pass the size of command to interpret.

In C, when you pass a string to a function, you’re not actually passing the full string, you’re passing a pointer to the first element in the string. This becomes an issue when you do sizeof(command), as you're just getting the size of the pointer and not the full string. If you try to loop over this string as done in the question, this can either lead to an underread, if you have a string longer than sizeof(char*), or a buffer overflow, if you have a string shorter than sizeof(char*). Generally, you shouldn’t use sizeof on pointers.

To fix your code, use strlen on the string you're passing to command in the calling function and do something similar to this:

char * interpret(char * command, int size){

char * ret = malloc(sizeof(char) * 100);
int counter = 0;
for(int i = 0; i < size; i  ) 
{ ...
  • Related