Merge lp:~compiz-team/compiz/compiz.fix_1018602 into lp:compiz/0.9.8

Proposed by Sam Spilsbury
Status: Superseded
Proposed branch: lp:~compiz-team/compiz/compiz.fix_1018602
Merge into: lp:compiz/0.9.8
Diff against target: 399 lines (+90/-90)
1 file modified
compizconfig/gsettings/src/gsettings.c (+90/-90)
To merge this branch: bzr merge lp:~compiz-team/compiz/compiz.fix_1018602
Reviewer Review Type Date Requested Status
Daniel van Vugt Needs Fixing
Review via email: mp+112681@code.launchpad.net

This proposal supersedes a proposal from 2012-06-28.

This proposal has been superseded by a proposal from 2012-06-29.

Description of the change

Fixes LP (#1018602) : An invalid read when using g_variant_iter_loop.

No tests yet, tests will be added to gsettings in another commit when the lcc testing work lands.

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Oops. There is a problem under case TypeMatch:
array is no longer initialized with zeros because you changed calloc to malloc. So the free() loop after it could potentially free an invalid pointer if g_variant_iter_loop doesn't find exactly nItems.

Also, strdup(value) is not necessary if you use:
     while (g_variant_iter_next (iter, "s", &value))
  *arrayCounter++ = value;
and then change the free() calls below it to g_free().

On that note, the variable variantType should be removed from readListValue. Just use "s", "i", "b" and "d" instead. It will be smaller, faster and more readable.

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Coolio, fixed the calloc issue, plugged a few other memleaks and fixed some gvariant errors I noticed.

I abstracted out the variantType stuff into a function - it should probably be transparent to the user as to the implementation detail of having to pass an arbitrary string to g_variant_get

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Thanks for the tip on using g_variant_iter_next ... that's now fixed too.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

The addition of compizconfigTypeToVariantType makes no sense.

We already have a tight coupling between:
    TYPE x;
and:
    g_variant_iter_loop (&iter, TYPESTRING, &x)

Using:
    g_variant_iter_loop (&iter, someVariable, &x)
only makes the code harder to read, with looser coupling and weaker cohesion.

Please remove compizconfigTypeToVariantType and just use:
    g_variant_iter_loop (&iter, "X", &x)

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

It's the same as:
    printf(secretFormatString, x, y, z);
It's too hard to read so adds maintenance risk.

Everyone would much prefer to read:
    printf("The results are: %d %s %f\n", x, y, z);

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

I think the printf analogy in this case doesn't apply here, the type string is merely an implementation detail - we know from the code what we want to extract already, and the type string is there to operate the valist API.

In any case, I'll change it.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Maybe. But back to the actual case of g_variant_iter_loop(I, F, V)... F and V are tightly coupled and need to match up so you should see the explicit value of F and type of V within the same block of code...

int v;
g_variant_iter_loop(&x, "i", &v)

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

I had another look at the code and variantType is more or less used as a placeholder so that copypasting was easier and so that we could return if there was no variant type for that setting. The fact that we are copypasting is a problem, but I modified the function so that it returns a boolean for whether or not we can read that type of setting.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

It works OK, but I can see some potentially serious mistakes:

203: "f" should be "d"
(http://developer.gnome.org/glib/2.30/glib-GVariant.html#GVariantClass)

235: Missing g_free() loop:
    for (i = 0; i < nItems; i++)
        if (array[i])
            g_free(array[i]);

239: g_free() on calloc'd block (214). Either change g_free() to free(), or calloc() to g_malloc0().

review: Needs Fixing
3268. By Sam Spilsbury

Plug memleak, s/g_free/free and s/"f"/"d"/

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

> It works OK, but I can see some potentially serious mistakes:
>
> 203: "f" should be "d"
> (http://developer.gnome.org/glib/2.30/glib-GVariant.html#GVariantClass)

Thanks, fixed.

>
> 235: Missing g_free() loop:
> for (i = 0; i < nItems; i++)
> if (array[i])
> g_free(array[i]);

My understanding is that g_variant_iter_next returns a shallow copy of the array, so free () is sufficient in this case (unlike the previous code where we copied the values out of the array. Valgrind reports there are no leaks here.

>
> 239: g_free() on calloc'd block (214). Either change g_free() to free(), or
> calloc() to g_malloc0().

Fixed, although I think g_malloc is a wrapper around malloc itself (eg, doesn't use g_slice_alloc)

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

No, you still need the g_free loop to free each array element after g_variant_iter_next:
  http://developer.gnome.org/glib/2.32/glib-GVariant.html#g-variant-iter-next
It's possible valgrind doesn't see the leak because the memory is managed by glib and freed at exit. But it's still a leak even still.

Also, I was referring to g_malloc0() to replace calloc. Not g_malloc(). :)

review: Needs Fixing
3269. By Sam Spilsbury

use g_strfreev

3270. By Sam Spilsbury

Merge lp:compiz

3271. By Sam Spilsbury

Plug other memleaks.

3272. By Sam Spilsbury

Merge lp:compiz

Unmerged revisions

3272. By Sam Spilsbury

Merge lp:compiz

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'compizconfig/gsettings/src/gsettings.c'
2--- compizconfig/gsettings/src/gsettings.c 2012-06-28 09:03:09 +0000
3+++ compizconfig/gsettings/src/gsettings.c 2012-06-29 06:32:20 +0000
4@@ -33,6 +33,31 @@
5
6 #include "gsettings.h"
7
8+static gboolean
9+compizconfigTypeHasVariantType (CCSSettingType type)
10+{
11+ gint i = 0;
12+
13+ static const unsigned int nVariantTypes = 6;
14+ static const CCSSettingType variantTypes[] =
15+ {
16+ TypeString,
17+ TypeMatch,
18+ TypeColor,
19+ TypeBool,
20+ TypeInt,
21+ TypeFloat
22+ };
23+
24+ for (; i < nVariantTypes; i++)
25+ {
26+ if (variantTypes[i] == type)
27+ return TRUE;
28+ }
29+
30+ return FALSE;
31+}
32+
33 static void
34 valueChanged (GSettings *settings,
35 gchar *keyname,
36@@ -121,10 +146,11 @@
37 GList *l = settingsList;
38 gchar *schemaName = getSchemaNameForPlugin (plugin);
39 GVariant *writtenPlugins;
40+ gsize writtenPluginsLen;
41+ gsize newWrittenPluginsSize;
42+ gchar **newWrittenPlugins;
43 char *plug;
44- GVariant *newWrittenPlugins;
45- GVariantBuilder *newWrittenPluginsBuilder;
46- GVariantIter *iter;
47+ GVariantIter iter;
48 gboolean found = FALSE;
49
50 while (l)
51@@ -143,6 +169,8 @@
52 return settingsObj;
53 }
54
55+ g_free (name);
56+
57 l = g_list_next (l);
58 }
59
60@@ -162,26 +190,31 @@
61
62 writtenPlugins = g_settings_get_value (currentProfileSettings, "plugins-with-set-keys");
63
64- newWrittenPluginsBuilder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
65+ g_variant_iter_init (&iter, writtenPlugins);
66+ newWrittenPluginsSize = g_variant_iter_n_children (&iter);
67
68- iter = g_variant_iter_new (writtenPlugins);
69- while (g_variant_iter_loop (iter, "s", &plug))
70+ while (g_variant_iter_loop (&iter, "s", &plug))
71 {
72- g_variant_builder_add (newWrittenPluginsBuilder, "s", plug);
73-
74 if (!found)
75 found = (g_strcmp0 (plug, plugin) == 0);
76 }
77
78 if (!found)
79- g_variant_builder_add (newWrittenPluginsBuilder, "s", plugin);
80-
81- newWrittenPlugins = g_variant_new ("as", newWrittenPluginsBuilder);
82- g_settings_set_value (currentProfileSettings, "plugins-with-set-keys", newWrittenPlugins);
83-
84- g_variant_iter_free (iter);
85- g_variant_unref (newWrittenPlugins);
86- g_variant_builder_unref (newWrittenPluginsBuilder);
87+ newWrittenPluginsSize++;
88+
89+ newWrittenPlugins = g_variant_dup_strv (writtenPlugins, &writtenPluginsLen);
90+
91+ if (writtenPluginsLen > newWrittenPluginsSize)
92+ {
93+ newWrittenPlugins = g_realloc (newWrittenPlugins, (newWrittenPluginsSize + 1) * sizeof (gchar *));
94+ newWrittenPlugins[writtenPluginsLen + 1] = g_strdup (plugin);
95+ newWrittenPlugins[newWrittenPluginsSize] = NULL;
96+ }
97+
98+ g_settings_set_strv (currentProfileSettings, "plugins-with-set-keys", (const gchar * const *)newWrittenPlugins);
99+
100+ g_free (schemaName);
101+ g_strfreev (newWrittenPlugins);
102
103 return settingsObj;
104 }
105@@ -276,36 +309,17 @@
106 readListValue (CCSSetting *setting)
107 {
108 GSettings *settings = getSettingsObjectForCCSSetting (setting);
109- gchar *variantType;
110+ gboolean hasVariantType;
111 unsigned int nItems, i = 0;
112 CCSSettingValueList list = NULL;
113 GVariant *value;
114- GVariantIter *iter;
115+ GVariantIter iter;
116
117 char *cleanSettingName = translateKeyForGSettings (setting->name);
118
119- switch (setting->info.forList.listType)
120- {
121- case TypeString:
122- case TypeMatch:
123- case TypeColor:
124- variantType = g_strdup ("s");
125- break;
126- case TypeBool:
127- variantType = g_strdup ("b");
128- break;
129- case TypeInt:
130- variantType = g_strdup ("i");
131- break;
132- case TypeFloat:
133- variantType = g_strdup ("d");
134- break;
135- default:
136- variantType = NULL;
137- break;
138- }
139+ hasVariantType = compizconfigTypeHasVariantType (setting->info.forList.listType);
140
141- if (!variantType)
142+ if (!hasVariantType)
143 return FALSE;
144
145 value = g_settings_get_value (settings, cleanSettingName);
146@@ -315,8 +329,8 @@
147 return TRUE;
148 }
149
150- iter = g_variant_iter_new (value);
151- nItems = g_variant_iter_n_children (iter);
152+ g_variant_iter_init (&iter, value);
153+ nItems = g_variant_iter_n_children (&iter);
154
155 switch (setting->info.forList.listType)
156 {
157@@ -324,14 +338,14 @@
158 {
159 Bool *array = malloc (nItems * sizeof (Bool));
160 Bool *arrayCounter = array;
161+ gboolean value;
162
163 if (!array)
164 break;
165-
166- /* Reads each item from the variant into the position pointed
167- * at by arrayCounter */
168- while (g_variant_iter_loop (iter, variantType, arrayCounter))
169- arrayCounter++;
170+
171+ /* Reads each item from the variant into arrayCounter */
172+ while (g_variant_iter_loop (&iter, "b", &value))
173+ *arrayCounter++ = value;
174
175 list = ccsGetValueListFromBoolArray (array, nItems, setting);
176 free (array);
177@@ -341,14 +355,14 @@
178 {
179 int *array = malloc (nItems * sizeof (int));
180 int *arrayCounter = array;
181+ gint value;
182
183 if (!array)
184 break;
185-
186- /* Reads each item from the variant into the position pointed
187- * at by arrayCounter */
188- while (g_variant_iter_loop (iter, variantType, arrayCounter))
189- arrayCounter++;
190+
191+ /* Reads each item from the variant into arrayCounter */
192+ while (g_variant_iter_loop (&iter, "i", &value))
193+ *arrayCounter++ = value;
194
195 list = ccsGetValueListFromIntArray (array, nItems, setting);
196 free (array);
197@@ -358,14 +372,14 @@
198 {
199 double *array = malloc (nItems * sizeof (double));
200 double *arrayCounter = array;
201+ gdouble value;
202
203 if (!array)
204 break;
205-
206- /* Reads each item from the variant into the position pointed
207- * at by arrayCounter */
208- while (g_variant_iter_loop (iter, variantType, arrayCounter))
209- arrayCounter++;
210+
211+ /* Reads each item from the variant into arrayCounter */
212+ while (g_variant_iter_loop (&iter, "d", &value))
213+ *arrayCounter++ = value;
214
215 list = ccsGetValueListFromFloatArray ((float *) array, nItems, setting);
216 free (array);
217@@ -374,23 +388,20 @@
218 case TypeString:
219 case TypeMatch:
220 {
221- char **array = calloc (1, (nItems + 1) * sizeof (char *));
222- char **arrayCounter = array;
223+ gchar **array = calloc (1, (nItems + 1) * sizeof (gchar *));
224+ gchar **arrayCounter = array;
225+ gchar *value;
226
227 if (!array)
228- {
229 break;
230- }
231-
232- /* Reads each item from the variant into the position pointed
233- * at by arrayCounter */
234- while (g_variant_iter_loop (iter, variantType, arrayCounter))
235- arrayCounter++;
236+
237+ array[nItems] = NULL;
238+
239+ /* Reads each item from the variant into arrayCounter */
240+ while (g_variant_iter_next (&iter, "s", &value))
241+ *arrayCounter++ = value;
242
243 list = ccsGetValueListFromStringArray (array, nItems, setting);
244- for (i = 0; i < nItems; i++)
245- if (array[i])
246- free (array[i]);
247 free (array);
248 }
249 break;
250@@ -402,7 +413,7 @@
251 if (!array)
252 break;
253
254- while (g_variant_iter_loop (iter, variantType, &colorValue))
255+ while (g_variant_iter_loop (&iter, "s", &colorValue))
256 {
257 memset (&array[i], 0, sizeof (CCSSettingColorValue));
258 ccsStringToColor (colorValue,
259@@ -417,7 +428,6 @@
260 }
261
262 free (cleanSettingName);
263- free (variantType);
264
265 if (list)
266 {
267@@ -638,8 +648,7 @@
268 char *pathName)
269 {
270 GSettings *settings = getSettingsObjectForCCSSetting (setting);
271- GVariant *value;
272- gchar *variantType = NULL;
273+ GVariant *value = NULL;
274 CCSSettingValueList list;
275
276 char *cleanSettingName = translateKeyForGSettings (setting->name);
277@@ -651,7 +660,6 @@
278 {
279 case TypeBool:
280 {
281- variantType = "ab";
282 GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ab"));
283 while (list)
284 {
285@@ -664,7 +672,6 @@
286 break;
287 case TypeInt:
288 {
289- variantType = "ai";
290 GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ai"));
291 while (list)
292 {
293@@ -677,7 +684,6 @@
294 break;
295 case TypeFloat:
296 {
297- variantType = "ad";
298 GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ad"));
299 while (list)
300 {
301@@ -690,7 +696,6 @@
302 break;
303 case TypeString:
304 {
305- variantType = "as";
306 GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
307 while (list)
308 {
309@@ -703,7 +708,6 @@
310 break;
311 case TypeMatch:
312 {
313- variantType = "as";
314 GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
315 while (list)
316 {
317@@ -716,7 +720,6 @@
318 break;
319 case TypeColor:
320 {
321- variantType = "as";
322 GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
323 char *item;
324 while (list)
325@@ -732,11 +735,10 @@
326 default:
327 printf("GSettings backend: attempt to write unsupported list type %d!\n",
328 setting->info.forList.listType);
329- variantType = NULL;
330 break;
331 }
332
333- if (variantType != NULL)
334+ if (value)
335 {
336 g_settings_set_value (settings, cleanSettingName, value);
337 g_variant_unref (value);
338@@ -919,15 +921,15 @@
339 char *currentProfilePath;
340 GVariant *newProfiles;
341 GVariantBuilder *newProfilesBuilder;
342- GVariantIter *iter;
343+ GVariantIter iter;
344 gboolean found = FALSE;
345
346 profiles = g_settings_get_value (compizconfigSettings, "existing-profiles");
347
348 newProfilesBuilder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
349
350- iter = g_variant_iter_new (profiles);
351- while (g_variant_iter_loop (iter, "s", &prof))
352+ g_variant_iter_init (&iter, profiles);
353+ while (g_variant_iter_loop (&iter, "s", &prof))
354 {
355 g_variant_builder_add (newProfilesBuilder, "s", prof);
356
357@@ -941,7 +943,6 @@
358 newProfiles = g_variant_new ("as", newProfilesBuilder);
359 g_settings_set_value (compizconfigSettings, "existing-profiles", newProfiles);
360
361- g_variant_iter_free (iter);
362 g_variant_unref (newProfiles);
363 g_variant_builder_unref (newProfilesBuilder);
364
365@@ -1155,15 +1156,15 @@
366 GVariant *newProfiles;
367 GVariantBuilder *newProfilesBuilder;
368 char *plugin, *prof;
369- GVariantIter *iter;
370+ GVariantIter iter;
371 char *profileSettingsPath = g_strconcat (PROFILEPATH, profile, "/", NULL);
372 GSettings *profileSettings = g_settings_new_with_path (PROFILE_SCHEMA_ID, profileSettingsPath);
373
374 plugins = g_settings_get_value (currentProfileSettings, "plugins-with-set-keys");
375 profiles = g_settings_get_value (compizconfigSettings, "existing-profiles");
376
377- iter = g_variant_iter_new (plugins);
378- while (g_variant_iter_loop (iter, "s", &plugin))
379+ g_variant_iter_init (&iter, plugins);
380+ while (g_variant_iter_loop (&iter, "s", &plugin))
381 {
382 GSettings *settings;
383
384@@ -1189,13 +1190,12 @@
385 }
386
387 /* Remove the profile from existing-profiles */
388- g_variant_iter_free (iter);
389 g_settings_reset (profileSettings, "plugins-with-set-values");
390
391- iter = g_variant_iter_new (profiles);
392+ g_variant_iter_init (&iter, profiles);
393 newProfilesBuilder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
394
395- while (g_variant_iter_loop (iter, "s", &prof))
396+ while (g_variant_iter_loop (&iter, "s", &prof))
397 {
398 if (g_strcmp0 (prof, profile))
399 g_variant_builder_add (newProfilesBuilder, "s", prof);

Subscribers

People subscribed via source and target branches