0

When I compile and run this program on Windows/Eustis I am not getting any errors or warnings.

The basic function of the program is to read in an input text file(source code) and strip out C-style comments /*........*/ to a file cleaninput.txt.

It works on Windows. However, when run on Eusis I get this:

gcc -o out.x a2.c
./out.x 
*** stack smashing detected ***: ./out.x terminated
Aborted

I have tried compiling with the command

gcc -fno-stack-protector -o out.x a2.c
./out.x
*** Error in './out.x': double free or corruption (out): 0x09670440 ***
Aborted

Is there a program or utility I can use to figure this out?

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


#define MAX_DEC_LENGHT 11
#define MAX_INTEGER 99999
#define MAX_LINE_WIDTH 100      //used in the struct below defines how wide a instruction can be per line

FILE *fp;


typedef struct input{
    char line[MAX_LINE_WIDTH];
    struct input *next;
}input;

void scanFile();
struct input *Push(struct input *temp2, char Buff[MAX_LINE_WIDTH]);
void printClean(struct input *temp);
int Get_No_Lines();
void freeme(struct input* ptr);
const char  *strip_comments(char input[MAX_LINE_WIDTH]);




int main(){
    int x = Get_No_Lines();
    scanFile(x);        //will read in the input and produce cleaninput.txt, get_no_lines is used to tell the program later how long the input text file is
    return(0);
}




/*
Take in an integer N, which represents how many lines there are in the text file, which is used in scanning into a linked list of each line
calls for the print clean input function
Currently not returning anything
*/
void scanFile(int n){   
    fp = fopen("input.txt", "r");
    struct input*temp = NULL;

    int i;

    for(i=0;i<n;i++){
        char Buff[MAX_LINE_WIDTH];
        fgets(Buff,MAX_LINE_WIDTH,fp);          //fgets is by far the easiest solution i found to scanning in line by line, the linked list is there for unlimited input lenght
        temp = Push(temp,Buff);     //push the value of fgets onto the linked list
    }
    printClean(temp);
    freeme(temp);               //at this point we call the printClean input function
    fclose(fp); 
}

/*
Take in the the pointer to a linked list, and place the value buff into the structs line segment,
Basic function is linked list push to end
*/
struct input *Push(struct input *temp2, char Buff[MAX_LINE_WIDTH]){
    struct input *temp=(struct input*)malloc(sizeof(struct input));
    struct input *current = temp2;
    strcpy(temp->line,Buff);
    temp->next= NULL;
        if(temp2==NULL){
            return(temp);       //base case if null
        }

        while(current->next!=NULL){
            current = current->next;        //insert to back of list
        }   
    current->next = temp;           //link the new node
    return(temp2);                  
}

/*
The main driver function for stripping the comments out of the input text file, 
calls the strip_comments function and places the result back into the struct, then prints to the file stream
currently not returing anythig, shouldnt need to, will be checked later -MM 
*/
void printClean(struct input *temp){
    fp = fopen("cleaninput.txt", "w");
    while(temp!=NULL){
        char t[MAX_LINE_WIDTH];
        strcpy(t,strip_comments(temp->line));                   //copy the contents of strip_comments into t, and then copy the contents of t into temp->line
        strcpy(temp->line, t);                                  //yeah im not sure why i need to strcpy's but it wouldnt work without them \_(?)_/¯
        fputs(temp->line, fp);
        temp=temp->next;        
    }
    fclose(fp);
}


const char *strip_comments(char input[MAX_LINE_WIDTH]){ 
    char output[100];

    int i=0;
    int x =0;

    int inComment = 0;  // a boolean variable to let the case statment change behavior in the while loop

    while(i<=MAX_LINE_WIDTH){
        if(inComment==1){
            if(input[i]=='*' && input[i+1]=='/'){
                inComment=0;
                i++;                                    //end the comment, and increment the counter up two to clear hte comment 
                i++;
            }
        }   
        if(inComment==0){
            if(input[i]=='/'&& input[i+1]=='*'){            //condtion to enter the comment switch
                inComment=1;                                            
        }else{              
            output[x] = input[i];           //if not in the comment and last check was not in comment push the value of input[i] to output[x] increment x
            x++;
        }
    }

        i++;
    }
    char *rtn = output;
    return(rtn);            //return the input free of comments, currently cannot handle multi_line comments
}


/*
Used for the scanning function, its sole purpose is to let the program know how many lines there are in the input text file
*/
int Get_No_Lines(){
    fp = fopen("input.txt", "r");

    int ch, number_of_lines = 0;
        do 
        {
            ch = fgetc(fp);
            if(ch == '\n')
                number_of_lines++;          //if the scanner gets to a \n charecter increment
        } while (ch != EOF);

        if(ch != '\n' && number_of_lines != 0)          // needs to be checked, method was adopted from the internet 
            number_of_lines++;  

    if(number_of_lines==0){     //i added this case in when we get a one line input that the user has not hit the /n or enter key
        number_of_lines =1; 
    }    

    fclose(fp);
    return(number_of_lines);
}

void freeme(struct input* ptr){
    struct input *temp;
    while(ptr!=NULL){
        temp=ptr->next;
        strcpy(ptr->line,"");
        free(ptr);
        ptr=temp;
    }
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
hockeyfreak863
  • 59
  • 3
  • 12
  • You're assuming that lines are no longer than 100 characters and that a comment doesn't span several lines. The line by line storage is an unnecessary complication, and you don't even need to read the entire file and store it just to strip comments. – molbdnilo Oct 14 '15 at 07:36
  • i found the error to be inside of the strip_comments function, i changed the data structure from dynamic to static and got the same result, then started commenting out methods, found out that it was in the strip_comments area... will post my solution when i fix it for future info – hockeyfreak863 Oct 14 '15 at 07:44
  • the fix was to change const char *strip_comments(char input[MAX_LINE_WIDTH]) to const char *strip_comments(char input[500]){ – hockeyfreak863 Oct 14 '15 at 07:46
  • Those two prototypes are equivalent - the parameter is actually a pointer, and the number inside `[]` is ignored by the compiler. You must have changed something else as well. – molbdnilo Oct 14 '15 at 07:49
  • `input` seems like a horrible typedef name, since you have several variables named input as well. Maybe change this to `input_t`. – Lundin Oct 14 '15 at 08:20
  • @hockeyfreak863 You haven't fixed anything with that, you still have a major bug. You merely dodged the bug by luck the one time you re-built and executed the program. See my posted answer for an actual solution. – Lundin Oct 14 '15 at 08:24

1 Answers1

1

You are returning a pointer to the local variable char output[100];, which invokes undefined behavior. Returning a pointer to a local variable is always a severe bug.

Instead, pass the output buffer as a parameter to the function and leave the allocation to the caller.

Can a local variable be accessed outside its scope?

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396