赋值运算符中的无效 free() / delete / delete[] / realloc() 错误

Invalid free() / delete / delete[] / realloc() error in assignment operator

我是编程新手,当我尝试 运行 使用 Valgrind 的程序时,我遇到了这样的错误。我用谷歌搜索了几个小时来解决这个问题。请你能告诉我我要去哪里错了吗?希望赋值运算符附近有一些错误。

错误:

==5130== Invalid read of size 8
==5130==    at 0x400CFD: std::passwd::~passwd() (passwd.c++:18)
==5130==    by 0x400C06: main (p1.c++:21)
==5130==  Address 0x5a1c040 is 0 bytes inside a block of size 8 free'd
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D16: std::passwd::~passwd() (passwd.c++:19)
==5130==    by 0x400BFA: main (p1.c++:17)
==5130== 
==5130== Invalid free() / delete / delete[] / realloc()
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D07: std::passwd::~passwd() (passwd.c++:18)
==5130==    by 0x400C06: main (p1.c++:21)
==5130==  Address 0x5a1c420 is 0 bytes inside a block of size 8 free'd
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D07: std::passwd::~passwd() (passwd.c++:18)
==5130==    by 0x400BFA: main (p1.c++:17)
==5130== 
==5130== Invalid free() / delete / delete[] / realloc()
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D16: std::passwd::~passwd() (passwd.c++:19)
==5130==    by 0x400C06: main (p1.c++:21)
==5130==  Address 0x5a1c040 is 0 bytes inside a block of size 8 free'd
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D16: std::passwd::~passwd() (passwd.c++:19)
==5130==    by 0x400BFA: main (p1.c++:17)
==5130== 
==5130== 
==5130== HEAP SUMMARY:
==5130==     in use at exit: 120 bytes in 1 blocks
==5130==   total heap usage: 7 allocs, 8 frees, 729 bytes allocated
==5130== 
==5130== Searching for pointers to 1 not-freed blocks
==5130== Checked 192,896 bytes
==5130== 
==5130== 120 bytes in 1 blocks are still reachable in loss record 1 of 1
==5130==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x53C0024: getdelim (iogetdelim.c:66)
==5130==    by 0x5444B52: getpass (getpass.c:97)
==5130==    by 0x400F84: std::passwd::get() (passwd.c++:66)
==5130==    by 0x400B3C: main (p1.c++:9)
==5130== 
==5130== LEAK SUMMARY:
==5130==    definitely lost: 0 bytes in 0 blocks
==5130==    indirectly lost: 0 bytes in 0 blocks
==5130==      possibly lost: 0 bytes in 0 blocks
==5130==    still reachable: 120 bytes in 1 blocks
==5130==         suppressed: 0 bytes in 0 blocks
==5130== 
==5130== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
==5130== 
==5130== 1 errors in context 1 of 3:
==5130== Invalid free() / delete / delete[] / realloc()
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D16: std::passwd::~passwd() (passwd.c++:19)
==5130==    by 0x400C06: main (p1.c++:21)
==5130==  Address 0x5a1c040 is 0 bytes inside a block of size 8 free'd
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D16: std::passwd::~passwd() (passwd.c++:19)
==5130==    by 0x400BFA: main (p1.c++:17)
==5130== 
==5130== 
==5130== 1 errors in context 2 of 3:
==5130== Invalid free() / delete / delete[] / realloc()
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D07: std::passwd::~passwd() (passwd.c++:18)
==5130==    by 0x400C06: main (p1.c++:21)
==5130==  Address 0x5a1c420 is 0 bytes inside a block of size 8 free'd
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D07: std::passwd::~passwd() (passwd.c++:18)
==5130==    by 0x400BFA: main (p1.c++:17)
==5130== 
==5130== 
==5130== 1 errors in context 3 of 3:
==5130== Invalid read of size 8
==5130==    at 0x400CFD: std::passwd::~passwd() (passwd.c++:18)
==5130==    by 0x400C06: main (p1.c++:21)
==5130==  Address 0x5a1c040 is 0 bytes inside a block of size 8 free'd
==5130==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5130==    by 0x400D16: std::passwd::~passwd() (passwd.c++:19)
==5130==    by 0x400BFA: main (p1.c++:17)
==5130== 
==5130== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

这是头文件passwd.h

#include<stdio.h>
#include<iostream>
#ifndef MIN_PASSWD_LEN
#define MIN_PASSWD_LEN 6
#endif
#ifndef MAX_PASSWD_LEN
#define MAX_PASSWD_LEN 20
#endif
#ifndef NO_OF_NUMBERS
#define NO_OF_NUMBERS 1
#endif
#ifndef NO_OF_ALPHABETS
#define NO_OF_ALPHABETS 1
#endif
#ifndef NO_OF_SYMBOLS
#define NO_OF_SYMBOLS 1
#endif
namespace std{
  class passwd{
   char **pwd;
  public:
   passwd& operator=(const passwd);
   passwd();
   ~passwd();
   bool check_validity();
   void tochar(char **);
   void get();
 };
}

上述头文件的函数:passwd.c++

#include<iostream>
#include"passwd.h"
#include<string.h>
#include<unistd.h>
#include<stdlib.h>

using namespace std;

passwd::passwd()
{
  pwd=(char **)malloc(sizeof(char*));
  pwd[0]=(char *)malloc(9);
  strcpy(pwd[0],"password");
}

passwd::~passwd()
{
   free(pwd[0]);
   free(pwd);
}

passwd& passwd::operator=(const passwd pswd)
{
  pwd[0]=(char *)realloc(pwd[0],strlen(*pswd.pwd)+1);
  strcpy(pwd[0],*pswd.pwd);
  return *this;
}

bool passwd::check_validity()
{
  if(strlen(pwd[0])<=MAX_PASSWD_LEN&&strlen(pwd[0])>=MIN_PASSWD_LEN);
  else
    return false;
    int number_count=0,alphabet_count=0,symbol_count=0;
    for(int i=0;i<strlen(pwd[0]);i++)
     {
        if(pwd[0][i]<='9'&&pwd[0][i]>='0')
         {
            number_count++;
         }
        else if((pwd[0][i]>='a'&&pwd[0][i]<='z')||(pwd[0][i]>='A'&&pwd[0][i]<='Z'))
          {
            alphabet_count++;

          }
        else if(pwd[0][i]>32&&pwd[0][i]!=127)
          {
            symbol_count++;
          }
      }
if(number_count>=NO_OF_NUMBERS&&alphabet_count>=NO_OF_ALPHABETS  && symbol_count>=NO_OF_SYMBOLS)
      return true;
    else
      return false;
}

void passwd::tochar(char **pswd)
{
  *pswd=(char*)malloc(strlen(pwd[0])+1);
  strcpy(*pswd,pwd[0]);
}

void passwd::get()
{
  char *pswd;
  pswd=getpass("");
  pwd[0]=(char *)realloc(pwd[0],strlen(pswd)+1);
  strcpy(pwd[0],pswd);
}

主程序:p1.c++

#include"passwd.h"
#include<iostream>
#include<stdlib.h> 
int main()
{
  using namespace std;
  passwd p;
  cout<<"Enter password: ";
  p.get();
  if(p.check_validity())
    cout<<"Valid pwd.\n";
  else
    cout<<"Invalid pwd.\n";
  char *s;
  p.tochar(&s);
  cout<<s<<endl;
  passwd x=p;
  free(s);
  x.tochar(&s);
  cout<<s<<endl;
  free(s);
}

你的密码 class 有一个隐式定义的复制构造函数。如果你不明确创建一个看起来有点像

的构造函数
passwd(const passwd &other)

然后编译器自动生成一个简单地复制所有成员的。所以当你这样做时

passwd x=p;

然后你有效地做到了 x.pwd = p.pwd;。因此,当第二个 passwd 被销毁时,您将再次释放 pwd[0]pwd

为了解决这个问题,显式定义一个复制构造函数来执行您想要它执行的操作(可能分配一个新的 pwdpwd[0],然后将密码复制到其中)。或者,或者,定义一个 private 复制构造函数以防止它被使用。或者,如果您使用的是现代构造函数,则可以在 class 声明中使用 passwd(const passwd &other) = delete; 显式删除复制构造函数。请注意,后两个选项将使 passwd x = p; 出错。

即使您 passwd x; x = p; 由于另一个问题,这也会中断:您的 operator= 没有引用原始文件,因此在调用它时会创建一个副本。通常人们会定义一个 operator=(const passwd &pswd) - 通过省略 & 必须制作参数的副本,这是使用复制构造函数完成的,然后在 [=40= 之后导致双重释放] 来自 operator= 并且复制的 pswd 被销毁。