Segfault with std::list usage

自闭症网瘾萝莉.ら 提交于 2019-12-25 00:24:44

问题


I'm Java user coming over to C++, and I am having a hard time understanding what is going wrong with this statement. My program has been segfaulting anywhere I put the push_back command. So I'm wondering what exactly is going on.

class Process {
  public:
    int nice;
    int arrivalTime;
    int cpuBursts;
    list<int> burstList;

    Process() {
      burstList.push_back(10); // Segfaults here...
   }  
}; 

Here is the full code:

#include<iostream>
#include<stdlib.h>
#include<fstream>
#include<list>
#include<string.h>

using namespace std;

int calcTimeslice(int priority);
int calcOriginalPrio(int nice);
int readFile(int ,char **);
int calcPrioBonus(int,int);
void tokenizeAndAdd(char *);

class Bursts {
  public:
    int isCPUBurst;
    int time;

    Bursts() {}
    // Constructor to make it easier to add to list
    Bursts(int tempIsCPU, int tempTime) {
      isCPUBurst = tempIsCPU;
      time = tempTime;
    }

};

class Process {
  public:
    int nice;
    int arrivalTime;
    int cpuBursts;
    list<int> burstList;

    Process() {
      burstList.push_back(10);
   }
};



int main(int arg, char **argv) {

  // This is if the file was not correctly read into the program
  // or it doesnt exist ...
  if(readFile(arg,argv)==-1) {
    cout << "File could not be read. \n";
    return -1;
  }
  //cout << "Original Calc Whatever: " << calcOriginal(19) << '\n';
  return 0;

}

/*
 *  Calculates the timeslice based on the priority
 */
int calcTimeslice(int priority) {
  double finalCalc;

  // This is the given function in the prompt
  finalCalc = ( (1 - (priority / 140)) * 290 + (.5) ) + 10;

  // Cast to int, this will be a truncate
  return ((int)finalCalc);
}

int readFile(int arg, char **argv) { 
  char *temp,*pointer;
  int endOfFile = 1;

  // While its not the end of the file
  while(endOfFile) {
    // Read in the input from stdin
    fgets(temp,256,stdin);

    // Check to see if this line had a * in it
    if(*temp =='*')
      endOfFile = 0;
    else
      tokenizeAndAdd(temp);
  }

  return 0; 

}

void tokenizeAndAdd(char *string) {
  char *token = strtok(string," \n"); 
  int i = 0;
  Process p;

  while(token != NULL) {
    cout << token << endl;
    if(i>2) {  // If it is odd (CPU burst)
      if(i%2 == 1) {
        int tempInt = atoi(token);
        //p.burstList.push_back(tempInt); 
      }
      else { // If it is even (IO burst)
        int tempInt = atoi(token);
        //p.burstLis.push_back(tempInt); 
      }      
    }
    else if(i==0)
      p.nice = atoi(token);
    else if(i==1)
      p.arrivalTime = atoi(token);
    else if(i==2)
      p.cpuBursts = atoi(token);

    token = strtok(NULL," \n");
    i++;
  }

  //cout << p.nice << " " << p.arrivalTime << " " << p.cpuBursts << "\n";
  //i = 0;
  //cout << p.burstList.size() << "\n";
  //  cout << 
  //}
  return;
}

/*
 *  Calculates and returns the original priority based on the nice number
 *    provided in the file.
 */
int calcOriginalPrio(int nice) {
  double finalCalc;

  // This is the given function from the prompt
  finalCalc = (( nice + 20 ) / 39 ) * 30 + 105.5;

  // Cast to int, this is a truncate in C++
  return ((int)finalCalc);
}

/* 
 * Calculates the bonus time given to a process
 */
int calcPrioBonus(int totalCPU, int totalIO) {
  double finalCalc;

  // How to calculate bonus off of the prompt
  if(totalCPU < totalIO)
    finalCalc = ( (1 - (totalCPU / (double)totalIO)) * (-5)) - .5;
  else
    finalCalc = ( (1 - (totalIO / (double)totalCPU)) * 5) + .5;

  // Cast to int
  return ((int)finalCalc);
}

回答1:


You are using temp uninitialized in the following code:

char *temp;
...
while(endOfFile) {
  fgets(temp,256,stdin);
  ...

This can have any side effect, since it most likely destroys your stack or parts of the heap memory. It could fail immediately (when calling the fgets() function), it could fail later (as in your sample) or it could even run fine - maybe until you upgrade your OS, your compiler or anything else, or until you want to run the same executable on another machine. This is called undefined behaviour.

You need to allocate space for the temp variable, not a pointer only. Use something like

char temp[256];
...
while(endOfFile) {
  fgets(temp,256,stdin);
  ...

For more information, see the fgets() documentation. The first parameter is a pointer to a char array - that is where fgets() will store the bytes which have been read. In your code, you pass an uninitialized pointer which means that fgets() will store the bytes to an undefined memory location - this is catched by the OS which terminates your application with a segmentation fault.


BTW: You should consider enabling pedantic warnings when compiling - I compiled with

g++ -Wall -pedantic -o list list.cpp

which gave me the following warning:

list.cpp: In function 'int readFile(int, char**)':
list.cpp:76:26: warning: 'temp' may be used uninitialized in this function [-Wuninitialized]



回答2:


This is probably not the actual code with the error you report. But here is one of the problems with give you UB.

  char *temp,*pointer; // uninicialized pointer  char temp[1000]; could work?
  int endOfFile = 1;

  // While its not the end of the file
  while(endOfFile) {
    // Read in the input from stdin
    fgets(temp,256,stdin);

The last function call will read a maximum of 256 bytes from stdin and will write it in the memory pointed by pointer tmp. So, you need to first "prepare" that memory. But with char *tmp; you only define a pointer, with no defined value, that is, with point to some possible unexisting or illegal/inaccessible for you memory. In contrary, char tmp[1000]; will define in the "stack memory" a block of 1000 bytes, with you can point to using simple the variable tmp. Hope this is clear for you.
EDIT:

I don't know why that would change the behavior of the list, 

You are right. That is Undefined Behavior (UB). When you write in some unknown memory (pointed by an uninitialized pointer) you may overwrite data or even code that will broke somewhere the correct function of your program in an unpredicted way. You will need to learn more about pointers but better you use std::string, and look how parse your file using string and stringstream. That will manage for you the memmory,



来源:https://stackoverflow.com/questions/15289662/segfault-with-stdlist-usage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!