Thread: Segmentation fault - IPC

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    26

    Segmentation fault - IPC

    I've been working on this assignment for class and the professor doesn't seem to like to help to much. He'll listen to you and not give you any answers, so it would be a big help if you could help nail down my problem area.

    The purpose of the code is to use an IPC to communicate between the parent and child process and have the parent read from a file and have the child write what the parent reads.

    The code is a little lenghtly, but I'm pretty sure I'm getting the segmentation fault right at the dup2 function in send_file, right around line 230.

    Again, thank you for any help, it's greatly appreciated.

    Code:
    /**********************************************************************
    
       File          : cse473-p1.c
    
       Description   : This is the main file for pipe-based IPC
                       (see .h for applications)
    
       Last Modified : Jan 1 09:54:33 EST 2009
       By            : Trent Jaeger
    
    ***********************************************************************/
    /**********************************************************************
    Copyright (c) 2008 The Pennsylvania State University
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
    
        * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
        * Neither the name of The Pennsylvania State University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    ***********************************************************************/
    
    /* Include Files */
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <assert.h>
    
    /* Project Include Files */
    #include "cse473-p1.h"
    
    /* Definitions */
    #define CLIENT_USAGE "cse473-p1 <input> <output>"
    #define TRUE 1
    #define STDIN 0
    #define STDOUT 1
    
        /* 
           send contents of a file to another process via IPC 
           or should it be multiple passes...
        */
    
    /**********************************************************************
    
        Function    : main
        Description : this is the main function for project #1 pipe IPC
        Inputs      : argc - number of command line parameters
                      argv - the text of the arguments
        Outputs     : 0 if successful, -1 if failure
    
    ***********************************************************************/
    
    /* Functions */
    int main( int argc, char **argv ) 
    {
        int pid;
        int read_index = 0, write_index = 0, new_index = 0;
        int err;
    
        /* Check for arguments */
        if ( argc < 3 ) 
        {
            /* Complain, explain, and exit */
            fprintf( stderr, "missing or bad command line arguments\n" );
            fprintf( stderr, CLIENT_USAGE );
            exit( -1 );
        }
    
        /* get the index for the IPC object */
        err = create_ipc( &read_index, &write_index );
        if ( err ) {
          fprintf( stderr, "create ipc error\n" );
          exit(-1);
        }
    
        /* create receiver process */
        if (( pid = fork() != 0 )) {
          /* child */
    	  printf("in the child\n");
          /* setup the IPC channel */
          setup_ipc_child( read_index, write_index,  &new_index );
          if ( err ) {
            fprintf( stderr, "child: error in ipc setup\n" );
    	exit(-1);
          }
    
          /* dump the file contents */
          rcv_file( argv[2], new_index );
          fprintf( stderr, "child: finished\n" );
        }
        else {
          /* parent */
    
          /* setup the IPC channel */
          err = setup_ipc_parent( read_index, write_index, &new_index );
          if ( err ) {
            fprintf( stderr, "parent: error in ipc setup\n" );
    	exit(-1);
          }
    	
          /* send the file contents */
          send_file( argv[1], new_index );
          fprintf( stderr, "parent: finished\n" );
        }
    
        exit( 0 );
    }
    
    
    /**********************************************************************
    
        Function    : create_ipc
        Description : obtain the descriptor to the new IPC channel 
        Inputs      : read and write index pointers (ignore the value)
        Outputs     : >0 if successful, <0 otherwise
    
    ***********************************************************************/
    
    int create_ipc( int *read, int *write )
    {
      int result;
      int fd[2];
    
      /* YOUR CODE HERE */
    	  
      if( pipe(fd) < 0)
      {
        result = -1;
      }
      
      *read = fd[0];
      *write = fd[1];
      
      return result;
    }
    
    
    /**********************************************************************
    
        Function    : setup_ipc_child
        Description : Using the IPC descriptor 'index', create a 'new' descriptor for reading data
        Inputs      : read -- read descriptor for pipe
                      write -- write descriptor for pipe 
                      new -- pointer to holder of new descriptor on output
        Outputs     : 0 if successful, <0 otherwise
    
    ***********************************************************************/
    
    int setup_ipc_child( int read, int write, int *new ) 
    {
      int err = 0; 
    
      /* YOUR CODE HERE */
      close(STDOUT); /*close normal stdin */
      close(write); /* close write side of pipe */
      
      if((*new = dup(read)) < 0)
    	return -1;
    	
    	
      
      return err;
    }
    
    
    /**********************************************************************
    
        Function    : setup_ipc_parent
        Description : Using the IPC descriptor 'index', create a 'new' descriptor for writing data
        Inputs      : read -- read descriptor for pipe
                      write -- write descriptor for pipe 
                      new -- pointer to holder of new descriptor on output
        Outputs     : 0 if successful, <0 otherwise
    
    ***********************************************************************/
    
    int setup_ipc_parent( int read, int write, int *new ) 
    {
      int err = 0;
    
      /* YOUR CODE HERE */
      close(STDIN); /* close normal stdout */
      close(read); /*close read side of pipe */
      
      if((*new = dup(write)) < 0)
    	return -1;; /* redirect stdout to write side of pipe and return value of stdout via new */
    
      return err;
    }
    
    
    /**********************************************************************
    
        Function    : send_file
        Description : Send file 'name' data over IPC channel 'index'
        Inputs      : name -- file path
                      index -- IPC descriptor
        Outputs     : 0 if successful, -1 otherwise
    
    ***********************************************************************/
    
    int send_file( char *name, int index )
    {
    
      /* YOUR CODE HERE */
      char c;
      FILE *inputFile;
      inputFile = fopen(name, "r");
    
      
      
      dup2(index, STDOUT);
      
      while( (c = getc(inputFile)) != EOF)
      {
    	   printf("%c", c);
      }
      
      return 0;
    }
    
    
    /**********************************************************************
    
        Function    : rcv_file
        Description : Receive file 'name' data over IPC channel 'index'
        Inputs      : name -- file path
                      index -- IPC descriptor
        Outputs     : 0 if successful, -1 otherwise
    
    ***********************************************************************/
    
    
    int rcv_file( char *name, int index )
    {
    	printf("firstline\n");
      /* YOUR CODE HERE */
      FILE *outFile;
      outFile = fopen(name, "w");
      
      char c;
      
      dup2(index, STDIN);
      
      while( (c = getc(STDIN)) != EOF)
      {
    	fprintf(outFile, "%c", c); // write to output file
      }
      
      return 0;
    }

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    I see a few problems, one of which will almost certainly segfault. First...

    In create_ipc(), if the call to pipe() succeeds, you'll be returning an indeterminate value to the caller. Notice how the variable "result" is never initialized. This means it contains junk. The only time you assign is on pipe() failure. Therefore when pipe() succeeds, "result" still contains junk which is returned to the caller.

    Next, in main(), you have the following:
    Code:
    if (( pid = fork() != 0 )) {
    This is equivalent to:
    Code:
    if ( pid = (fork() != 0 )) {
    This means that pid will be either 0 or 1. Since you never actually use the pid in your code, it "works", but it's only by accident. You instead want:
    Code:
    if ( (pid = fork()) != 0 ) {
    This correctly stores the return value of fork() into pid, rather than storing the result of the != operator.

    Next, In rcv_file() your "c" is a char, but it should be an int, which is what getc() returns. The reason for this is so that getc() can tell you when it reached EOF or error. On typical systems, one of two things will happen if "c" is a char: either a regular character will signal EOF (usually ÿ, at least in latin1), or the loop will never terminate. If you make "c" an int, all will be fine.

    I also noticed two comments that don't seem to match up with the code:
    Code:
    close(STDOUT); /*close normal stdin */
    close(STDIN); /* close normal stdout */
    Finally, the code that's probably causing your segfault. In rcv_file() you're calling getc(STDIN), but STDIN is defined to be 0, which happens to be a null pointer in pointer context; and getc() expects a pointer (specifically, a FILE*). You should be calling getc(stdin) or just getchar().

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    26
    Thank you for the input, a lot of that makes sense. The comments with closing stdin and stdout are incorrect, because my roomate showed me I was closing the wrong ones in the wrong functions but never updated the comments. I have to get to class so I'll have to tinker with this in a few hours, which is when I'll bring updates.

    Again, thank you for the thorough response,

    ~kb

  4. #4
    Registered User
    Join Date
    Jan 2009
    Posts
    26
    Okay, so I've been looking at your suggestions and I'll just go down the list.

    The first one is what you said in create_ipc function. I was thinking the same thing you were, but it looks like my professor made a minor mistake when creating the main function he provided us with.

    In main...

    Code:
    err = create_ipc( &read_index, &write_index );
        if ( err ) {
          fprintf( stderr, "create ipc error\n" );
          exit(-1);
        }
    but then in create_ipc function, the comments say that it should return -1 on error, or 1 on success. But if you return 1 on success, then the if statement in main..

    Code:
    if ( err ) {
          fprintf( stderr, "create ipc error\n" );
          exit(-1);
        }
    would succeed...which shouldn't happen.

    So because of this I changed the declaration of result in the create_ipc function to instantiate it to 0. Then that if statement shouldn't trigger unless the pipe fails.

    I'm not really sure what to say about your comments on pid and fork inside the main function. The professor supplied us with main which we aren't really supposed to alter, but I mean everyone makes mistakes. so right now I changed it to your suggestion.

    As for the last part, I feel so dumb lol. When my roommate was looking at my code he told me to change it form an int to a char.

    So all in all, I altered according to your suggestions, it compiled fine, and didn't get any errors when I gave it an input file and told it the output file to write to.

    I then went ahead and did diff mtest mtestout (mtest was input file, mtestout was output file) and go no errors!!! So everything is working fine.

    Thank you so very much for helping me, it truly is appreciated. Unfortunately for me there are 2 more parts that deal with IPC, one with linux, and one with linux shared memory. So you'll probably see me again sometime in the near future.

    Again, I can't thank you enough, this saves me a lot of time and aggrivation.

    ~kb

    EDIT: (extra question)

    Out of curiosity, I noticed that 'c' is also declared as a character in send_file(). Could this be an issue? Should it be set as an int? Right now c is a char in send_file but an int in rcv_file like you informed me to do.
    Last edited by kbfirebreather; 01-29-2009 at 02:59 PM. Reason: update: extra question

  5. #5
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    So because of this I changed the declaration of result in the create_ipc function to instantiate it to 0. Then that if statement shouldn't trigger unless the pipe fails.
    Absolutely correct. This is the typical way of indicating success on unix-like systems.
    The professor supplied us with main which we aren't really supposed to alter, but I mean everyone makes mistakes. so right now I changed it to your suggestion.
    Yeah, it looked to me like it was supplied code... So unfortunately you can't always be sure that what you're learning is completely correct. As long as you're always learning with a dose of skepticism (and that applies to what you read here, too, of course) then you're on the right course.
    Out of curiosity, I noticed that 'c' is also declared as a character in send_file(). Could this be an issue? Should it be set as an int? Right now c is a char in send_file but an int in rcv_file like you informed me to do.
    Good catch; you're right. The return value of getc() (and getchar()/fgetc()) should always be stored in an int. The only exception would be if you're absolutely positive that you will not get EOF, but heck, I'd use an int even then. I guess the point is: do things the "right" way unless you really can't (eg, restrictions due to hardware, etc).
    Again, I can't thank you enough, this saves me a lot of time and aggrivation.
    You're quite welcome.

  6. #6
    Registered User
    Join Date
    Jan 2009
    Posts
    1

    Part 2

    Yo dude......kbfirebreather
    Do u have the 2nd part of the project done? I am too in the same class...but I am having some problems with reads. Could you please post your code for PART 2 so that I can find out what is the problem with my program ?

    Help will be greatly appreciated!!!!!

  7. #7
    Registered User
    Join Date
    Jan 2009
    Posts
    26
    Hey, I actually made another thread, if you have any input, please reply

    http://cboard.cprogramming.com/showt...753#post831753

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Yeah, and "yo dude" might want to think about the fact that tutors are known to monitor message boards for such blatant attempts to plagiarise someone else's work.

    > your code for PART 2 so that I can find out what is the problem with my program ?
    Yeah, right.
    Like looking at a finished cake can tell you anything about how to bake one.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. segmentation fault... first time with unix...
    By theMethod in forum C Programming
    Replies: 16
    Last Post: 09-30-2008, 02:01 AM
  2. Segmentation fault
    By bennyandthejets in forum C++ Programming
    Replies: 7
    Last Post: 09-07-2005, 05:04 PM
  3. Segmentation fault
    By NoUse in forum C Programming
    Replies: 4
    Last Post: 03-26-2005, 03:29 PM
  4. Locating A Segmentation Fault
    By Stack Overflow in forum C Programming
    Replies: 12
    Last Post: 12-14-2004, 01:33 PM
  5. Segmentation fault...
    By alvifarooq in forum C++ Programming
    Replies: 14
    Last Post: 09-26-2004, 12:53 PM