在Eratosthenes算法的Sieve中,某些数字导致free()到分段错误

时间:2013-10-14 07:40:05

标签: c algorithm memory-leaks sieve-of-eratosthenes

我的问题是这段代码大部分时间都运行良好,但是如果我输入n的某些值(我发现的一些是1000和111)它会给我一个SIGSEGV错误(我想你就是这么说的) 。我发现当在标记上调用free时会发生错误,所以我使用n = 1000在程序上运行valgrind,但我不知道该怎么做,或者如何解决这个错误。我真的在寻找如何解决这个bug的答案,不一定是在算法本身,但它应该是Eratosthenes筛选的实现。谢谢大家 代码:

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


    int *eSieve(int n) 
    {
        /*first number of the array is the number of primes*/
        int i = 0;
        int *num = 0;
        int *marks = 0;
        int *primes = 0;
        int k = 1;
        int m = 0;
        int j = 0;
        int nPrimes = 0;

        num = malloc(sizeof(int) * n);
        marks = malloc(sizeof(int) * n);

        for (i = 0;i < n;i++) {
            num[i] = i + 1;
            marks[i] = 0;
        } 

        marks[0] = 2; /*mark 1 as special */
        i = 1;
        /*1 is prime, 2 is composit*/
        while (k <= (int) sqrt(n)) {
            if (marks[k] == 0) {
                m = num[k]; 
                for (i = 2; j < n; i++) {
                    j = (m * i) - 1;
                    marks[j] = 1;
                }
            j = 0;
            }
            k++;    
        }
        /*Count the primes*/
        for (i = 0;i < n;i++) {
            if (marks[i] == 0) {
                nPrimes++; 
            }
        }

        primes = malloc(sizeof(int) * (nPrimes + 1));
        primes[0] = nPrimes;
        j = 1;
        for (i = 0;i < (n);i++) {
            if (marks[i] == 0) {
                primes[j] = num[i];        
                j++;
            }
        }
        free(num);
        free(marks);
        return primes;
    }

    int main(int argc, char **argv)
    {
        int i = 0;
        int n = 0;
        int *primes = 0;
        if (argc < 2) {
            printf("Need a number argument");
        } else if (atoi(argv[1]) == 1) {
            printf("Enter Num > 1");
        } else if (atoi(argv[1]) < 0) {
            printf("Enter a positive value");
        } else {
            n = atoi(argv[1]);
        }

        primes = eSieve(n);

        for (i = 0;i < primes[0];i++) {
            printf("%d, ", primes[i+1]);
        }
        printf("\nNumber of Primes: %d\n", primes[0]);
        return 0;
    }

Valgrind输出

==3970== Memcheck, a memory error detector
==3970== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==3970== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3970== Command: ./sieve 1000
==3970== 
==3970== Invalid write of size 4
==3970==    at 0x400837: eSieve (sieve.c:34)
==3970==    by 0x4009EF: main (sieve.c:76)
==3970==  Address 0x5502fc4 is 4 bytes after a block of size 4,000 alloc'd
==3970==    at 0x4C2C74C: malloc (vg_replace_malloc.c:270)
==3970==    by 0x400777: eSieve (sieve.c:19)
==3970==    by 0x4009EF: main (sieve.c:76)
==3970== 
--3970-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--3970-- si_code=1;  Faulting address: 0x105502FE0;  sp: 0x4030dad60

valgrind: the 'impossible' happened:
   Killed by fatal signal
==3970==    at 0x38061648: unlinkBlock (m_mallocfree.c:290)
==3970==    by 0x380620C3: vgPlain_arena_malloc (m_mallocfree.c:1607)
==3970==    by 0x38028474: vgMemCheck_new_block (mc_malloc_wrappers.c:263)
==3970==    by 0x3802860A: vgMemCheck_malloc (mc_malloc_wrappers.c:301)
==3970==    by 0x3809C800: vgPlain_scheduler (scheduler.c:1665)
==3970==    by 0x380AB9EC: run_a_thread_NORETURN (syswrap-linux.c:103)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable
==3970==    at 0x4C2C74C: malloc (vg_replace_malloc.c:270)
==3970==    by 0x4008B1: eSieve (sieve.c:47)
==3970==    by 0x4009EF: main (sieve.c:76)


Note: see also the FAQ in the source distribution.
It contains workarounds to several common problems.
In particular, if Valgrind aborted or crashed after
identifying problems in your program, there's a good chance
that fixing those problems will prevent Valgrind aborting or
crashing, especially if it happened in m_mallocfree.c.

If that doesn't help, please report this bug to: www.valgrind.org

In the bug report, send all the above text, the valgrind
version, and what OS and version you are using.  Thanks.

错误讯息:

sieve: malloc.c:2369: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.

3 个答案:

答案 0 :(得分:1)

我没有检查整个逻辑,但以下循环可能是个问题。

for (i = 2; j < n; i++) {
  j = (m * i) - 1;
  marks[j] = 1;
}

您首先访问标记[j],然后检查j&lt; Ñ

而是添加支票。

for (i = 2; j < n; i++) {
  j = (m * i) - 1;
  if ( j < n )
    marks[j] = 1;
}

答案 1 :(得分:1)

此处j可能会大于n中的marks[j] = 1;malloc可能会写入已分配内存的控制块,并导致free / {{1时出错}} / realloc

    for (i = 2; j < n; i++) {
        j = (m * i) - 1;
        marks[j] = 1;
    }

<强>编辑:

我建议你把它改成这个:

    for (j = m * 2 - 1; j < n; j += m)
        marks[j] = 1;

答案 2 :(得分:0)

您试图在未分配给 marks[]的内存位置进行写入。

这应该可以解决问题:

 for (i = 2; (j = (m * i) - 1) < n; i++) {
                    marks[j] = 1;
 }