malloc 后大小 8 的无效写入

Invalid write of size 8 after a malloc

我目前正在为我的学校做一个项目,我的代码有问题。该程序的目的是实现一个插件管理器,该插件管理器在目录中搜索所有“*_plugin.so”文件并将插件描述符添加到一个简单的链表中。

C代码:

      //struct of a single node
      typedef
      struct _chainon_ { 
        plugin_descriptor * desc;
        struct _chainon_ * next;
    } Chainon;

      // manager that contains sentry node & number of plugins contained by the list
      struct plugin_manager_t {
        int nbElts;  
        Chainon * sentinel;
    };

  typedef 
  struct {
    const char *    m_name;     // nom du filtre
    const char *    m_description;  // description de l'effet du filtre
    filter_function m_filtre;       // fonction de réalisation du filtre
  } plugin_descriptor;

现在 register_plugin 函数,当程序在目录中找到一个新插件时调用它,它调用一个调用 register_plugin 的 init_ 函数:

  void
  init_(plugin_manager * pm)
  {
    register_plugin(pm,
            "null_filter",
            "Exemple de filtre inutile",
            null_filter);
  }

然后应该将新插件添加到列表中:

  void
  register_plugin(plugin_manager * pm,
          const char filter_name[],
          const char filter_description[],
          filter_function the_filter)
  {
      Chainon * n = (Chainon *)malloc(sizeof(Chainon)); //new node that i want to add to the linked list
      n->desc = NULL;
      n->next = NULL;
      n->desc->m_name = filter_name;
      n->desc->m_description = filter_description;
      n->desc->m_filtre = the_filter;
      Chainon * current = pm->sentinel;
      for(int i=0;i<pm->nbElts;i++){
        current=current->next;
        i++;
      }
      current->next = n;
  }

这就是我在执行此程序时使用 valgrind 得到的结果:

> ==7022== Invalid write of size 8
> ==7022==    at 0x4015A7: register_plugin (pluginmanager.cc:165)
> ==7022==    by 0x66E1BDC: init_ (null_filter_plugin.cc:23)
> ==7022==    by 0x401483: discover_plugins (pluginmanager.cc:113)
> ==7022==    by 0x401187: main (main.cc:17)
> ==7022==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
> ==7022== 
> ==7022== 
> ==7022== Process terminating with default action of signal 11 (SIGSEGV)
> ==7022==  Access not within mapped region at address 0x0
> ==7022==    at 0x4015A7: register_plugin (pluginmanager.cc:165)
> ==7022==    by 0x66E1BDC: init_ (null_filter_plugin.cc:23)
> ==7022==    by 0x401483: discover_plugins (pluginmanager.cc:113)
> ==7022==    by 0x401187: main (main.cc:17)
> ==7022==  If you believe this happened as a result of a stack
> ==7022==  overflow in your program's main thread (unlikely but
> ==7022==  possible), you can try to increase the size of the
> ==7022==  main thread stack using the --main-stacksize= flag.
> ==7022==  The main thread stack size used in this run was 8388608.

我是C编程新手

但是我不明白为什么我不能初始化"n->desc->name",因为我用malloc分配了内存,然后把所有的东西都初始化为NULL?

任何帮助将不胜感激!

谢谢

您的代码有几个问题,其中一些是小问题,另一些是导致发布的 valgrind 输出的原因,

  1. 不是问题,只是你don't need to cast the return value of malloc()

    Chainon *n = malloc(sizeof(Chainon));
    

    可以,不需要强制转换

  2. 您需要检查 malloc() 是否成功,而不仅仅是假设它成功了,在正常情况下它不会失败,但如果失败,您的程序不会处理它,并且如果它有一些敏感数据需要存储在硬盘驱动器或任何其他需要干净退出的情况下,你会给程序用户带来很多问题,所以你应该确保你的程序干净退出,因此检查 malloc() 的 return 值是一件非常好的事情,只需在每次调用 malloc() 后立即检查 NULL 并根据失败的情况进行处理发生。

  3. 你不为你的结构成员分配space,每个指针在取消引用之前必须指向有效的内存,所以你必须确保它确实指向有效的内存,未初始化的指针无法检查,因此如果您要在可能的检查后初始化指针,请将其初始化为 NULL.

    您在一种情况下这样做,但随后取消引用 NULL 指针,这是未定义的行为。

使用上面的所有建议,你的函数必须像这样重写*

void
register_plugin(plugin_manager * pm,
                const char *const filter_name,
                const char *const filter_description,
                filter_function the_filter)
{
    Chainon           *chainon;
    plugin_descriptor *descriptor;
    Chainon           *current
    int                i;
    if (pm == NULL)
        return;
    chainon = malloc(sizeof(*chainon));
    if (chainon == NULL)
        return;
    chainon->next = NULL;

    descriptor = malloc(sizeof(*descriptor));
    if (descriptor == NULL)
     {
        free(chainon);
        return;
     }
    chainon->desc = descriptor;

    descriptor->m_name        = filter_name;
    descriptor->m_description = filter_description;
    descripotor->m_filtre     = the_filter;

    current = pm->sentinel;
    if (current == NULL)
        return;
    for(i = 0 ; ((i < pm->nbElts) && (current->next != NULL)) ; ++i)
        current = current->next;
    current->next = chainon;
}

*我改的有些东西其实不是必须的。我只是觉得这样更好。