I'm receiving a very strange segfault on line 94
Code:
char buffer[256];
in the traverse method below, the first time it runs. This is very strange and I have no idea what is causing it. I've debugged the program on XCode and see no problems, and I'm starting to think that it's a gcc bug.

Whatever it is is even causing Valgrind to segfault. Valgrind picks up several jumps based on uninitialized values within strcat. Is this a gcc bug, or does someone see a problem with my code?

Code:
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>

char * findTab(char * str){
    bool quote = false;
    for (;*str;++str){
	   switch(*str){
		  case '\\':
			 ++str;
			 if (!(*str)) return NULL;
			 break;
		  case '\"':
			 quote = !quote;
			 break;
		  case '\t':
			 if (!quote) return str;
			 break;
	   }
    }
    return NULL;
}

static bool tryfile(char * filename){
    printf("Working on %s... ", filename);
    
    char * ext = filename + strlen(filename) - 4;
    if (strcmp(ext, ".php")){
	   printf("skipping\n");
	   return false;  //not a PHP file
    }
    
    struct stat stbuf;
    stat(filename, &stbuf);
    
    FILE * fp = fopen(filename, "r");
    if (!fp){
	   printf("failed to open\n");
	   return false;
    }
    
    size_t characters = stbuf.st_size * 2;
    char * contents = (char*)malloc(characters * sizeof(char));
    size_t len = fread(contents, 1, stbuf.st_size, fp);
    fclose(fp);
    
    if (len != stbuf.st_size){
	   printf("load failed\n");
	   free(contents);
	   return false;
    }
    
    contents[len] = '\0';
    char * tab = findTab(contents);
    int tabs = 0;
    while (tab){
	   char * buffer = (char*)malloc(characters * sizeof(char));
	   memcpy(buffer, contents, ((long)tab - (long)contents) * sizeof(char));
	   strcat(buffer, "    ");
	   strcat(buffer, tab + 1);
	   strcpy(contents, buffer);
	   free(buffer);
	   if (strlen(contents) > characters - 10){
		  characters *= 2;
		  contents = (char*)realloc(contents, characters);
	   }
	   ++tabs;
	   tab = findTab(contents);
    }
    
    fp = fopen(filename, "w");
    if (!fp){
	   printf("failed to open for output\n");
	   free(contents);
	   return false;
    }
    
    size_t bytes = strlen(contents) * sizeof(char);
    size_t check = fwrite(contents, 1, bytes, fp);
    fclose(fp);
    free(contents);
    if (bytes != check){
	   printf("failed to write new file\n", tabs);
	   return false;
    }
    printf("done, replaced %d tabs\n", tabs);
    return true;
}

static bool traverse(char * name, bool recurse){
    char buffer[256];
    strcpy(buffer, name);
    strcat(buffer, "/");
    DIR * dir = opendir(name);
    if (dir){
	   struct dirent * dp;
	   if (!(dp = readdir(dir))) return false; //.
	   if (!(dp = readdir(dir))) return false; //..
	   while (dp = readdir(dir)){
		  if (dp -> d_name[0] != '.'){  //ignore hidden files and folders
			 strcpy(buffer, name);
			 strcat(buffer, "/");
			 strcat(buffer, dp -> d_name);
			 if ((!recurse) || (!traverse(buffer, recurse))){
				tryfile(buffer);
			 }
		  }
	   }
	   return true;
    }
    //not a directory
    return false;	
}

int main(int argc, char ** argv){
    printf("Checking parameter count\n");
    //check that the dir param is there
    if ((argc != 2) && (argc != 3)){
	   printf("You have to give this program a directory as an argument\n");
	   return 0;
    }
    
    printf("Checking for recursive param\n");
    bool recurse = false;
    if (argc == 3){
	   printf("Checking recursive param is correct\n");
	   if (strcmp(argv[2], "-r")){
		  printf("The correct parameters are %s file/dir [-r]\n", argv[0]);
		  return 0;
	   }
	   recurse = true;
    }
    
    printf("Starting %s\n", argv[1]);
    if (!traverse(argv[1], recurse)){
	   if (!tryfile(argv[1])){
		  printf("%s doesnt appear to exist or is not a directory\n", argv[1]);
		  return 0;
	   }
    }
    
    return 0;
}