1

I'm not sure why I'm getting Segmentation Fault: 11 when trying to compile this small C file:

#include <stdio.h>

#define MIN  97
#define MAX  122
#define DIFF 32

int main()
{
  int c = EOF;
  int i, j;
  int arr[MAX - MIN];

  for(i=MIN; i<=MAX; i++)
    arr[i] = 0;

  while((c = getchar()) != EOF) {
    if(c >= MIN)
      ++arr[c];
    else
      ++arr[c + DIFF];
  }

  for(i=MIN; i<=MAX; i++) {
    printf("|%c|", i);
    for(j=1; j<=arr[i]; j++)
      putchar('-');
    putchar('\n');
  }
  return 0;
}

I'm using Apple's built-in cc which is just Clang/Apple LLVM 10.0.0

This file compiles just fine on macOS 10.13.6, and I don't have any problems compiling any other C files/programs on 10.14; it's just this one file. From my beginner's point of view, this seems like a bug with the OS.

EDIT: This program is a slightly modified example from a K&R exercise I found here

rootbeersoup
  • 143
  • 3
  • 6
  • 1
    I think you want `++arr[c-MIN]`, for one thing. – Steve Summit Sep 29 '18 at 15:07
  • 2
    "I'm under the impression this is a bug with the OS." No, it's almost always a bug in your program. – Steve Summit Sep 29 '18 at 15:08
  • I didn't write the program - [it's an example someone else wrote](https://clc-wiki.net/wiki/K%26R2_solutions:Chapter_1:Exercise_14) for a K&R book exercise. It compiled and ran just fine before upgrading to macOS 10.14. – rootbeersoup Sep 29 '18 at 15:16
  • 1
    *I'm under the impression this is a bug with the OS* Very, very, very bad impression. A simple program like that is almost never going to uncover an operating system bug, especially not in an OS that's been around for a long time with literally hundreds of millions if not billions of users. – Andrew Henle Sep 29 '18 at 15:18
  • That's fine if the program is faulty. I'm just curious why it compiles and runs fine on 10.13.6 but not on 10.14 – rootbeersoup Sep 29 '18 at 15:19
  • 1
    What you are seeing is "undefined behavior". See https://stackoverflow.com/questions/7961067/how-undefined-is-undefined-behavior for just one question regarding that. – Andrew Henle Sep 29 '18 at 15:20
  • Because it invokes the UB and anything can happen(including ordering a pizza and transfer from your bank account) – 0___________ Sep 29 '18 at 15:20
  • @AndrewHenle if not OS maybe it is a compiler error :). OP forgot about this option – 0___________ Sep 29 '18 at 15:23
  • this statement: `for(i=MIN; i<=MAX; i++)` will access 1 past the end of the array. This will result in undefined behavior. – user3629249 Oct 02 '18 at 01:43
  • this: `int arr[MAX - MIN]; for(i=MIN; i<=MAX; i++) arr[i] = 0;` would be much better written as: int arr[MAX-MIN +1] = {0};` – user3629249 Oct 02 '18 at 01:44
  • regarding: `while((c = getchar()) != EOF) { if(c >= MIN) ++arr[c]; else ++arr[c + DIFF];` Any value from 0x00 through 0xFF can be input via `getchar()`. So this code can result in trying write past the end of the array, resulting in undefined behavior – user3629249 Oct 02 '18 at 01:47
  • regarding: `int arr[MAX - MIN];` This results in an array that is 1 too short AND statements like: `for(i=MIN; i<=MAX; i++)` Will then write up to 2 `int` locations past the end of the array – user3629249 Oct 02 '18 at 01:49

1 Answers1

2

With this line

int arr[MAX - MIN];

... you are creating an array of 25 (122 - 97) integers. The valid array indices are 0 ... 24.

First of all, since each array cell is dedicated to a lowercase letter, the array should have 26 cells.

Then, with this statement (and the next ones as well):

for (i = MIN; i <= MAX; i++) arr[i] = 0;

... you are writing into array cells arr[97] to arr[122] that do not exist, overwriting other parts of the program stack. That's why you get a segmentation fault.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
xhienne
  • 5,738
  • 1
  • 15
  • 34
  • Thanks for the reply. I noticed the array of 25 when I copy/pasted the code, but for whatever reason it ran fine before. I changed the array to 26, but I still receive the segmentation fault. – rootbeersoup Sep 29 '18 at 15:31
  • @rootbeersoup Your overlooked my last sentence. The main problem is that you are **never** writing into the allocated array, but past it, into another part of the stack, which overwrites precious data (like a return address) and triggers a segfault. – xhienne Sep 29 '18 at 15:37
  • @rootbeersoup The task could be done with an array size of 26 but not with the code as written. Look at the `for` loops, they assume that `MAX` is a valid array index. The array size would have to be at least 123. I suggest you find a different example to learn from, this one is badly broken. – Blastfurnace Sep 29 '18 at 15:45
  • @xhienne Ok, so after playing with it, an array of 123 or higher allows the program to run fine with no errors. If I set the array to 122 or lower (not sure the lowest allowed here), the program runs but throws `Abort trap: 6` upon pressing CTRL+D. I'm guessing this isn't idiomatic, it seems like a workaround for my shitty program. Is that right? – rootbeersoup Sep 29 '18 at 15:48
  • @Blastfurnace Thanks, that makes sense to me. I appreciate the advice, I was confused since the program worked fine for me before and assumed the code was fine. – rootbeersoup Sep 29 '18 at 15:52
  • @rootbeersoup As a quick workaround, it's ok to just change the size of the array (you are just wasting memory since the first 97 cells of the array are not used). In that case why would you use an array of less than 123 integers? – xhienne Sep 29 '18 at 16:04
  • @xhienne Is it correct to assume there's no way to get this program to execute as-is with an array of 26 integers? i.e. should this be rewritten entirely? – rootbeersoup Sep 29 '18 at 16:07
  • @rootbeersoup You can take a look at the [next example](https://clc-wiki.net/wiki/K%26R2_solutions:Chapter_1:Exercise_14#Solution_by_scopych) which uses an array of 26 elements. – xhienne Sep 29 '18 at 16:10