Search code examples
csegmentation-faultbus-error

Bus Error in C for Loop


I have a toy cipher program which is encountering a bus error when given a very long key (I'm using 961168601842738797 to reproduce it), which perplexes me. When I commented out sections to isolate the error, I found it was being caused by this innocent-looking for loop in my Sieve of Eratosthenes.

unsigned long i;
int candidatePrimes[CANDIDATE_PRIMES];
// CANDIDATE_PRIMES is a macro which sets the length of the array to
// two less than the upper bound of the sieve. (2 being the first prime
// and the lower bound.)

for (i=0;i<CANDIDATE_PRIMES;i++)
{

  printf("i: %d\n", i); // does not print; bus error occurs first

  //candidatePrimes[i] = PRIME;

}

At times this has been a segmentation fault rather than a bus error.

Can anyone help me to understand what is happening and how I can fix it/avoid it in the future?

Thanks in advance!

PS

The full code is available here:

http://pastebin.com/GNEsg8eb


Solution

  • The problem is that you're blowing the stack away.

    unsigned long i;
    int candidatePrimes[CANDIDATE_PRIMES];
    

    If CANDIDATE_PRIMES is large, this alters the stack pointer by a massive amount. But it doesn't touch the memory, it just adjusts the stack pointer by a very large amount.

    for (i=0;i<CANDIDATE_PRIMES;i++)
    {
    

    This adjusts "i" which is way back in the good area of the stack, and sets it to zero. Checks that it's < CANDIDATE_PRIMES, which it is, and so performs the first iteration.

    printf("i: %d\n", i); // does not print; bus error occurs first
    

    This attempts to put the parameters for "printf" onto the bottom of the stack. BOOM. Invalid memory location.

    What value does CANDIDATE_PRIMES have?

    And, do you actually want to store all the primes you're testing or only those that pass? What is the purpose of storing the values 0 thru CANDIDATE_PRIMES sequentially in an array???

    If what you just wanted to store the primes, you should use a dynamic allocation and grow it as needed.

    size_t g_numSlots = 0;
    size_t g_numPrimes = 0;
    unsigned long* g_primes = NULL;
    
    void addPrime(unsigned long prime) {
        unsigned long* newPrimes;
        if (g_numPrimes >= g_numSlots) {
            g_numSlots += 256;
            newPrimes = realloc(g_primes, g_numSlots * sizeof(unsigned long));
            if (newPrimes == NULL) {
                die(gracefully);
            }
            g_primes = newPrimes;
        }
        g_primes[g_numPrimes++] = prime;
    }