在malloc之后写入大小为8的无效

时间:2015-03-30 15:23:47

标签: c memory memory-leaks valgrind

我目前正在为我的学校开展一个项目,我的代码存在问题。该程序的目的是实现一个插件管理器,在一个目录中搜索所有" * _ 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编程的新手

但我不明白为什么我无法初始化&#34; n-&gt; desc-&gt; name&#34;既然我用malloc分配了内存,然后将所有内容初始化为NULL?

任何帮助都会受到赞赏!

谢谢

1 个答案:

答案 0 :(得分:2)

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

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

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

    没关系,不需要演员。

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

  3. 你没有为你的struct成员分配空间,每个指针必须在解除引用之前指向有效内存,所以你必须确保它确实指向有效内存,无法检查未初始化的指针,以防万一如果要在可能的检查后初始化指针,请将其初始化为NULL

    您可以在一种情况下执行此操作,但随后取消引用NULL指针,这是未定义的行为。

  4. 使用上述所有建议,您的函数必须像 *

    一样重写
    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;
    }
    

    * 我改变的一些事情并非真的有必要。我认为这样做更好。