为什么从 class 调用 printf 时会出现分段错误?

Why there is a segmentation fault when calling printf from a class?

这是我的源代码的相关部分(我认为)

#include <iostream>
#include <cstdarg>
#include <cstring>
#include <cstdlib>



class Poly
{
private:
    double *coefficients;
    size_t degree;
    inline double *cfp(size_t i);

public:
    Poly();
    Poly(size_t n, ...);

    void Print() const;
    ~Poly();
};

Poly::Poly()
{
    this->degree = 0;
    this->coefficients = new double(1);
    *(this->coefficients) = 1.;
}

Poly::Poly(size_t n, ...)
{
    va_list coefs;
    va_start(coefs, n);

    this->degree = n;
    n++;
    register double *cfs = new double(n);
    this->coefficients = cfs;
    
    while (n--)
    {
        *cfs = va_arg(coefs, double);
        cfs++;
    }

    va_end(coefs);
}

void Poly::Print() const
{
    bool started = false;
    double c = this->cf(0);
    putchar('a');
    std::cout << this->degree << '\n';
    if (c != 0.)
    {
        std::cout << c;
        started = true;
    }

    size_t N = this->degree;

    for (size_t i = 1; i <= N; i++)
    {
        c = this->cf(i);
        if (c != 0.)
        {
            if (!started)
                started = true;
            else
                std::cout << ((c < 0.) ? " - " : " + ");
                //printf(" + ");
            std::cout << fabs(c) << " x^" << i;
            //printf("%lf x^%lu", c, i);
        }
    }
    printf("\n");
}


Poly::~Poly()
{
    delete this->coefficients;
}

int main()
{
    //printf("\n");        <- Uncommenting this line stops the error
    Poly p1(7, 1., 3., -9., 2., 0., 8., -2., 6.);
    p1.Print();
}


现在,Print 方法有很多 printfcout。但是,当我取消注释来自 main 的行时,malloc 在第一个 printcout 甚至 putchar 中从“打印”方法中带来分段错误。我在那里找不到任何内存泄漏。为什么会发生以及如何预防?

我在 WSL Ubuntu 上使用 gcc (g++) 9.3.0。该程序使用标志 -lc -g.

编译

gdb 给我看了这个

malloc(): corrupted top size

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) backtrace 
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff7c0f859 in __GI_abort () at abort.c:79
#2  0x00007ffff7c7a3ee in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7da4285 "%s\n")
    at ../sysdeps/posix/libc_fatal.c:155
#3  0x00007ffff7c8247c in malloc_printerr (str=str@entry=0x7ffff7da2556 "malloc(): corrupted top size") at malloc.c:5347
#4  0x00007ffff7c8583a in _int_malloc (av=av@entry=0x7ffff7dd5b80 <main_arena>, bytes=bytes@entry=1024) at malloc.c:4107
#5  0x00007ffff7c872d4 in __GI___libc_malloc (bytes=1024) at malloc.c:3058
#6  0x00007ffff7c6ee84 in __GI__IO_file_doallocate (fp=0x7ffff7dd66a0 <_IO_2_1_stdout_>) at filedoalloc.c:101
#7  0x00007ffff7c7f050 in __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7dd66a0 <_IO_2_1_stdout_>) at libioP.h:948
#8  0x00007ffff7c7e0b0 in _IO_new_file_overflow (f=0x7ffff7dd66a0 <_IO_2_1_stdout_>, ch=97) at fileops.c:745
--Type <RET> for more, q to quit, c to continue without paging--
#9  0x00007ffff7c73482 in putchar (c=97) at putchar.c:28
#10 0x0000555555555cfe in Poly::Print (this=0x7fffffffdb90) at polynomial_r.cpp:241
#11 0x0000555555555fd2 in main () at test.cpp:7
(gdb) info frame
Stack level 0, frame at 0x7fffffffd6f0:
 rip = 0x7ffff7c3018b in __GI_raise (../sysdeps/unix/sysv/linux/raise.c:50); saved rip = 0x7ffff7c0f859
 called by frame at 0x7fffffffd820
 source language c.
 Arglist at 0x7fffffffd5c8, args: sig=sig@entry=6
 Locals at 0x7fffffffd5c8, Previous frame's sp is 0x7fffffffd6f0
 Saved registers:
  rip at 0x7fffffffd6e8
(gdb) 

看起来您通过写入超过堆分配的末尾破坏了堆。我认为你的问题在这里:

register double *cfs = new double(n);

请注意,上面的代码将单个 double 设置分配给值 n,而我认为您想要做的是分配 n 个双精度数组。为此,您需要使用方括号而不是圆括号:

register double *cfs = new double[n];