src/plugin.c: Assure that targets get dynamically allocated memory.
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 24 Feb 2009 09:08:29 +0000 (10:08 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 24 Feb 2009 09:15:36 +0000 (10:15 +0100)
If targets want to replace the values, they will have to use dynamically
allocated memory. If they can't free the values, because the pointer
might point to statically allocated memory, memory will be lost.

Unfortunately stack allocation will not do, since we will then not be able
to detect multiple replacements.

To impose as little a performance issue as possible, the dynamic allo-
cation is only done when either chain is present. If the filter mecha-
nism is not used, the values will not be copied.

src/plugin.c

index 9f42f2e..367c0d1 100644 (file)
@@ -837,9 +837,14 @@ int plugin_dispatch_values (value_list_t *vl)
        int status;
        static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
 
+       value_t *saved_values;
+       int      saved_values_len;
+
        data_set_t *ds;
 
-       if ((vl == NULL) || (*vl->type == '\0')) {
+       if ((vl == NULL) || (vl->type[0] == 0)
+                       || (vl->values == NULL) || (vl->values_len < 1))
+       {
                ERROR ("plugin_dispatch_values: Invalid value list.");
                return (-1);
        }
@@ -903,6 +908,31 @@ int plugin_dispatch_values (value_list_t *vl)
        escape_slashes (vl->type, sizeof (vl->type));
        escape_slashes (vl->type_instance, sizeof (vl->type_instance));
 
+       /* Copy the values. This way, we can assure `targets' that they get
+        * dynamically allocated values, which they can free and replace if
+        * they like. */
+       if ((pre_cache_chain != NULL) || (post_cache_chain != NULL))
+       {
+               saved_values     = vl->values;
+               saved_values_len = vl->values_len;
+
+               vl->values = (value_t *) calloc (vl->values_len,
+                               sizeof (*vl->values));
+               if (vl->values == NULL)
+               {
+                       ERROR ("plugin_dispatch_values: calloc failed.");
+                       vl->values = saved_values;
+                       return (-1);
+               }
+               memcpy (vl->values, saved_values,
+                               vl->values_len * sizeof (*vl->values));
+       }
+       else /* if ((pre == NULL) && (post == NULL)) */
+       {
+               saved_values     = NULL;
+               saved_values_len = 0;
+       }
+
        if (pre_cache_chain != NULL)
        {
                status = fc_process_chain (ds, vl, pre_cache_chain);
@@ -914,7 +944,17 @@ int plugin_dispatch_values (value_list_t *vl)
                                        status, status);
                }
                else if (status == FC_TARGET_STOP)
+               {
+                       /* Restore the state of the value_list so that plugins
+                        * don't get confused.. */
+                       if (saved_values != NULL)
+                       {
+                               free (vl->values);
+                               vl->values     = saved_values;
+                               vl->values_len = saved_values_len;
+                       }
                        return (0);
+               }
        }
 
        /* Update the value cache */
@@ -934,6 +974,15 @@ int plugin_dispatch_values (value_list_t *vl)
        else
                fc_default_action (ds, vl);
 
+       /* Restore the state of the value_list so that plugins don't get
+        * confused.. */
+       if (saved_values != NULL)
+       {
+               free (vl->values);
+               vl->values     = saved_values;
+               vl->values_len = saved_values_len;
+       }
+
        return (0);
 } /* int plugin_dispatch_values */