This is a program I wrote for class, and its completely done and compiles with no errors, but I keep getting a segmentation fault and even after using GDB and putting print lines (with fflush attached) I cannot figure out what the problem is. I do however think I found the right line.

The program itself reads in a mock MAL (MIPS Assembly Language) file and prints out a the same thing to the outfile with added line numbers and a variable reference table.

This is my code, there are two c files, one header, and a makefile, ill post everything but the makefile here.

This is the p4b.c file which contains my main() function. The problem isn't here but I figured I'd post it anyway just in case.

/* Program 4b -- This program reads MAL instructions and prints a reference table for them */

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

/* Main */
int main(int argc, char *argv[])
{

  /* prototypes */
  void xref(FILE*, FILE*);
  
  /* variable definitions */
  FILE * inf, * outf;
  
  /* check the number of command line arguments */
  if(argc != 3)
    {
      fprintf(stderr, "Incorrect number of command line arguments.\n Proper Usage: p4b infile outfile\n");
      exit(1);
    }
  /* open the infile for reading */
  if((inf = fopen(argv[1], "r")) == NULL)
    {
      fprintf(stderr, "Could not open %s (infile) for reading\n", argv[1]);
      exit(1);
    }
  /* open the outfile for writing */
  if((outf = fopen(argv[2], "w")) == NULL)
    {
      fprintf(stderr, "could not open %s (outfile) for writing\n", argv[2]);
      exit(1);
    }
  
  /* pass infile and outfile to be read/written in another function/file */
  xref(inf, outf);

  /* close the infile */
  if(fclose(inf) == EOF)
    {
      fprintf(stderr, "Could not close %s (infile)\n", argv[1]);
      exit(1);
    }
  /* close the outfile */
  if(fclose(outf) == EOF)
    {
      fprintf(stderr, "Could not close %s (outfile)\n", argv[2]);
      exit(1);
    }
  return 0;
}

This is the xref.c file which contains the xref() function, which is void, and takes two arguments, an in file and an out file.

/* Program 4b -- This program reads MAL instructions and prints a reference table for them */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "struct.h"

void xref(FILE * inf, FILE * outf)
{
  printf("1\n");fflush(stdout);/* POINT 1 */
  struct label malarray[100];
  int linenum, arrpos, count;
  char *str, *tmp;
  char linein[81];
  linenum = arrpos = 0;
  while(fgets(linein, 80, inf) != NULL)
    {
      printf("2\n");fflush(stdout);/* POINT 2 */
      linenum++;
      sprintf(str, "%c", linein[0]);
      if((strchr(str, '_') || isalpha(linein[0])) && (strchr(linein, ':') != NULL))
	{
	  printf("3\n");fflush(stdout);/* POINT 3 */
	  /* get the label name out of the string */
	  str = strtok(linein, ":");
	  /* find the next empty array location */
	  while(malarray[arrpos].flag == 1)
	    {
	      printf("4\n");fflush(stdout);/* POINT 4 */
	      arrpos++;
	    }
	  /* put the label name and line number into the struct array */
	  malarray[arrpos].flag = 1;
	  strcpy(str, malarray[arrpos].labelname);
	  malarray[arrpos].defline = linenum;
	}
      str = strtok(NULL, " ");
      str = strtok(NULL, " ");
      if(isalpha(str[0]) || (strstr(str, ",") != NULL))
	{
	  printf("5\n");fflush(stdout);/* POINT 5 */
	  while(isalpha(str[0]) || str[0] == '$')
	    {
	      printf("6\n");fflush(stdout);/* POINT 6 */
	      str = strtok(NULL, " ,");
	      arrpos = 0;
	      while(malarray[arrpos].flag == 1)
		{
		  printf("7\n");fflush(stdout);/* POINT 7 */
		  if(strcmp(malarray[arrpos].labelname, str) == 0)
		    {
		      printf("8\n");fflush(stdout);/* POINT 8 */
		      /* store the useline and incriment the watermark */
		      malarray[arrpos].useline[malarray[arrpos].uses] = linenum;
		      malarray[arrpos].uses++;
		    }
		  arrpos++;
		}
	    }
	}
    }
  rewind(inf);
  linenum = 1;
  while(fgets(linein, 81, inf) != NULL)
    {
      printf("9\n");fflush(stdout);/* POINT 9 */
      sprintf(str, "%d", linenum);
      strcat(str, linein);
      fputs(str, outf);
    }
  fputs("\n", outf);
  fputs("Cross Reference Table\n", outf);
  fputs("\n", outf);
  fputs("\tIdentifier\tDefinition\tUse\n", outf);
  arrpos = 0;
  while(malarray[arrpos].flag == 1)
    {
      printf("10\n");fflush(stdout);/* POINT 10 */
      strcpy(str, " ");
      /* put all the uselines into a string to print them to the outfile */
      while(count < malarray[arrpos].uses)
	{
	  printf("11\n");fflush(stdout);/* POINT 11 */
	  sprintf(tmp, "%d", malarray[arrpos].useline[count]);
	  strcat(str, tmp);
	  count++;
	}
      count = 0;
      fprintf(outf, "\t %s \t %d \t %s \n", malarray[arrpos].labelname, malarray[arrpos].defline, str);
    }
}

Lastly, though I don't think this has anything to do with the problem either, here is the struct.h header file that just contains a struct that I used to store information about each MAL variable in.

struct label
{
  int defline;
  int uses;
  int useline[100];
  char labelname[10];
  int flag;
};

When I run the file in my prompt this is what is printed to me:

$ ./p4b in.mal out.lst
1
2
Segmentation fault

The '1' and '2' that are printed are from the printf statements I put in to help myself trace the fault, which as far as I can tell point to it being in the if() statement on line 22 of xref.c.

The GDB output is as follows:

dyn-169-226-78-157:p4 adamrosscohen$ gdb --args ./p4b in.mal out.lst
GNU gdb 6.3.50-20050815 (Apple version gdb-1346) (Fri Sep 18 20:40:51 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries .. done

(gdb) run
Starting program: /Users/adamrosscohen/Desktop/p4/p4b in.mal out.lst
Reading symbols for shared libraries +. done
1
2

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x0000000000000000
0x00007fffffe007d9 in __memcpy ()
(gdb) backtrace
#0  0x00007fffffe007d9 in __memcpy ()
#1  0x00007fff8862ac05 in __sfvwrite ()
#2  0x00007fff8862a6dc in __vfprintf ()
#3  0x00007fff886de328 in vsprintf ()
#4  0x00007fff8865a447 in __sprintf_chk ()
#5  0x00000001000014be in xref (inf=0x7fff7107ee80, outf=0x7fff7107ef18) at xref.c:23
#6  0x000000010000139c in main (argc=3, argv=0x7fff5fbff9e0) at p4b.c:39

I still cannot figure out what is wrong with the program, but I now know it has something to do with memcpy(), which I'm not actually even calling.... anywhere in my program.

Anyone who could tell me why this is happening and/or how to fix it I would greatly appreciate it.
Thank you in advance,
A. Ross Cohen

Are you planning to point to memory you can write to before you write to it?

char *str, *tmp;
  char linein[81];
  linenum = arrpos = 0;
  while(fgets(linein, 80, inf) != NULL)
    {
      printf("2\n");fflush(stdout);/* POINT 2 */
      linenum++;
      sprintf(str, "%c", linein[0]);

So I'm pretty sure you mean I should try to use malloc to make a memory location for that pointer I made, but I tried it and it still segfaults. The segfault might be for a different reason this time though.

It compiles and I get the same output as before, but the GDB messages have changed a bit. Now they look like this:

mobilecone:p4 adamrosscohen$ gdb --args ./p4b in.mal out.lst
GNU gdb 6.3.50-20050815 (Apple version gdb-1346) (Fri Sep 18 20:40:51 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries .. done

(gdb) run 
Starting program: /Users/adamrosscohen/Desktop/p4/p4b in.mal out.lst
Reading symbols for shared libraries +. done
1
2

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x000000010000162c in xref (inf=0x7fff7107ee80, outf=0x7fff7107ef18) at xref.c:43
43	      if( (isalpha(str[0])) || (strstr(str, ",") != NULL) )
(gdb) backtrace
#0  0x000000010000162c in xref (inf=0x7fff7107ee80, outf=0x7fff7107ef18) at xref.c:43
#1  0x0000000100001380 in main (argc=3, argv=0x7fff5fbff9e0) at p4b.c:39

Are you planning to point to memory you can write to before you write to it?

char *str, *tmp;
  char linein[81];
  linenum = arrpos = 0;
  while(fgets(linein, 80, inf) != NULL)
    {
      printf("2\n");fflush(stdout);/* POINT 2 */
      linenum++;
      sprintf(str, "%c", linein[0]);

Unless you post your input file (or did I miss it?), I think we're all pretty limited to static analysis to try to help you out. That's rather tedious, so I wasn't going to wander very far into it, other than a quick look-see.

Unless you post your input file (or did I miss it?), I think we're all pretty limited to static analysis to try to help you out. That's rather tedious, so I wasn't going to wander very far into it, other than a quick look-see.

Whoops, I seem to have forgotten to post that.
Heres both the input file and the correct output file if the program were to work properly.

Input:

#A sample MAL program.
              .data                        #Data segment begins here.
avg:          .word                        #Will store the average. 
i1:           .word       20               #First integer. 
i2:           .word       13               #Second integer. 
i3:           .word       82               #Third integer. 
prompt:       .asciiz     "Value is: "
nl:           .byte       '\n'

              .text                        #Text segment begins here.
__start:      lw          $15,i1           #$15 contains 20.
              lw          $16,i2           #$16 contains 13.
i10:          add         $15,$15,$16      #Operand field has no ids.
              lw          $16,i3           #$16 contains 82.
              add         $15,$15,$16      #$15 contains the sum (115).
              li          $16,3            #$16 contains 3.
              div         $15,$15,$16      #$15 contains the average (38).
i20:          sw          $15,avg          #Store the average.
              puts        prompt
              put         avg
              putc        nl

              sw          $15,avg         
              la          $16,i1
              sw          $15,0($16)
              add         i3,i3,1         
              done                         #Similar to halt.

Correct Output:

1   #A sample MAL program.
2                 .data                        #Data segment begins here.
3   avg:          .word                        #Will store the average. 
4   i1:           .word       20               #First integer. 
5   i2:           .word       13               #Second integer. 
6   i3:           .word       82               #Third integer. 
7   prompt:       .asciiz     "Value is: "
8   nl:           .byte       '\n'

9                 .text                        #Text segment begins here.
10  __start:      lw          $15,i1           #$15 contains 20.
11                lw          $16,i2           #$16 contains 13.
12  i10:          add         $15,$15,$16      #Operand field has no ids.
13                lw          $16,i3           #$16 contains 82.
14                add         $15,$15,$16      #$15 contains the sum (115).
15                li          $16,3            #$16 contains 3.
16                div         $15,$15,$16      #$15 contains the average (38).
17  i20:          sw          $15,avg          #Store the average.
18                puts        prompt
19                put         avg
20                putc        nl

21                sw          $15,avg         
22                la          $16,i1
23                sw          $15,0($16)
24                add         i3,i3,1         
25                done                         #Similar to halt.

Cross Reference Table

    Identifier     Definition       Use
  
    avg              3             17  19  21
    i1               4             10  22
    i2               5             11
    i3               6             13  24
    prompt           7             18
    nl               8             20
    __start          10             
    i10              12            
    i20              17

btw, thank you again for your help.

Thanks for posting the input file.

I just did this for a quick "fix" at the str issue (I don't have your malloc update to the code, nor did I really want to use malloc):

char foo[100], *str = foo, *tmp;

But this only gets me past the if here:

if((strchr(str, '_') || isalpha(linein[0])) && (strchr(linein, ':') != NULL))
	{
	  printf("3\n");fflush(stdout);/* POINT 3 */
	  /* get the label name out of the string */
	  [B]str = strtok(linein, ":");[/B]
	  /* find the next empty array location */
	  while(malarray[arrpos].flag == 1)
	    {
	      printf("4\n");fflush(stdout);/* POINT 4 */
	      arrpos++;
	    }
	  /* put the label name and line number into the struct array */
	  malarray[arrpos].flag = 1;
	  strcpy(str, malarray[arrpos].labelname);
	  malarray[arrpos].defline = linenum;
	}

The if condition evaluates to false, so the contents are skipped. Unfortunately, this block contained the setup for strtok. So when it gets to here...

str = strtok(NULL, " ");
      str = strtok(NULL, " ");

... strtok hasn't been correctly set up to use NULL in subsequent calls.

And we've moved the segfault further down the road.

I prefer not to use strtok in parsing, and I found your code a little confusing. I might take a little bit different approach, something like this:

void xref(FILE * inf, FILE * outf)
{
   struct label malarray[100] = {0};
   int linenum = 0, arrpos = 0, count;
   char linein[81];
   /** Process the input file one line at at time.  */
   while ( fgets(linein, sizeof linein, inf) != NULL )
   {
      char *str = linein; /* Start at the beginning of the line. */
      /** Write each line to the output file. */
      fprintf(outf, "%-4d %s", ++linenum, str);
      /** Labels begin the line with an underscore or an alpha character.  */
      if ( isalpha(str[0]) || str[0] == '_' )
      {
         int n;
         /** Labels end with a colon ':'. */
         if ( sscanf(str, "%[^:]:%n", malarray[arrpos].labelname, &n) == 1 )
         {
            /** Found a label, do whatever. */
            malarray[arrpos].flag = 1;
            /** ... */

            /** Move the string pointer past the colon. */
            str += n + 1;
         }
      }
      /** Look at the remainder of the line for any previously found label. */
      for ( count = 0; count < arrpos && malarray[count].flag; ++count )
      {
         /** Found any?  */
         if ( strstr(str, malarray[count].labelname) )
         {
            /** Do stuff. */

         }
      }
      /** Bump the array counter. */
      if ( malarray[arrpos].flag == 1 )
      {
         ++arrpos;
      }
   }
   /** Generate the output file listing.  */

}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.