Merge lp:~jamesodhunt/upstart/bug-1222705-reprise into lp:upstart
- bug-1222705-reprise
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1656 |
Proposed branch: | lp:~jamesodhunt/upstart/bug-1222705-reprise |
Merge into: | lp:upstart |
Diff against target: |
304 lines (+45/-86) 3 files modified
ChangeLog (+8/-0) init/environ.c (+12/-14) init/tests/test_environ.c (+25/-72) |
To merge this branch: | bzr merge lp:~jamesodhunt/upstart/bug-1222705-reprise |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Dimitri John Ledkov | Needs Information | ||
Steve Langasek | please review memoves against (potentially) nih_alloced char** array | Pending | |
Review via email: mp+226983@code.launchpad.net |
Commit message
Description of the change
Colin Watson (cjwatson) wrote : | # |
memcpy is unsafe for that, but the entire point of memmove is to be safe in this situation.
Dimitri John Ledkov (xnox) wrote : | # |
memmove's are all good. Not sure if it's safe to use them against nih_alloced objects, given they have NihAllocCtx after them. Someone else should review this bit. See also the inline comment.
- 1657. By James Hunt
-
* init/environ.c: environ_remove(): Shrink memory to fit what we're
actually using.
* init/tests/test_environ. c: test_remove(): Remove now-invalid ENOMEM
checks.
James Hunt (jamesodhunt) wrote : | # |
It's safe because all the environ_*() calls operate on the result of nih_str_
Subsequent to nih_str_array_new() being called, that zero-sized array will be increased in size by calls to environ_add(), which in turn calls nih_str_
So, if the array contains pointers to 10 env vars, it has size 11 (10 + 1 for the NULL terminator), and has a single NihAllocCtx just before the zeroth element. So it's actual byte size is:
sizeof (NihAllocCtx) + (sizeof (char *) * (number_of_elements + 1))
As such, it is safe to call memmove to shuffle those pointers since they are the user-accessible way to reference the strings the array points to - Nih keeps track itself using the NihAllocCtx object.
I've added a call to nih_relloc() to compact the size of the array (from NIH's perspective) as it is wasteful (but not actually incorrect) not to call nih_realloc() and leave 'sizeof (char *)' bytes lying around until the array eventually gets deallocated.
Colin Watson (cjwatson) wrote : | # |
I agree with your analysis re NihAllocCtx. This looks right, and the form of the new code matches a similar section from environ_add, so that's good. Just one style comment.
James Hunt (jamesodhunt) wrote : | # |
To be convinced this fix works:
$ mkdir /tmp/conf /tmp/log
$ cat >>/tmp/conf/bug-1222705.conf<<EOT
start on startup
exec sleep 999
post-stop exec initctl unset-env wibble
EOT
$ gdb --args init/init --confdir /tmp/conf --logdir /tmp/log --debug
(gdb) run
In separate window:
$ initctl list-sessions
$ UPSTART_
- 1658. By James Hunt
-
* init/environ.c: environ_remove(): Style tweak courtesy of cjwatson's
review.
James Hunt (jamesodhunt) wrote : | # |
Thanks - style tweak applied.
Preview Diff
1 | === modified file 'ChangeLog' | |||
2 | --- ChangeLog 2014-07-11 21:32:38 +0000 | |||
3 | +++ ChangeLog 2014-07-16 15:55:55 +0000 | |||
4 | @@ -1,3 +1,11 @@ | |||
5 | 1 | 2014-07-16 James Hunt <james.hunt@ubuntu.com> | ||
6 | 2 | |||
7 | 3 | * init/environ.c: environ_remove(): | ||
8 | 4 | - Ensure removed entry is deref'd (LP: #1222705). | ||
9 | 5 | - Avoid recreating array. | ||
10 | 6 | * init/tests/test_environ.c: test_remove(): Add checks to ensure | ||
11 | 7 | removed entry freed as expected. | ||
12 | 8 | |||
13 | 1 | 2014-07-11 James Hunt <james.hunt@ubuntu.com> | 9 | 2014-07-11 James Hunt <james.hunt@ubuntu.com> |
14 | 2 | 10 | ||
15 | 3 | * NEWS: Release 1.13 | 11 | * NEWS: Release 1.13 |
16 | 4 | 12 | ||
17 | === modified file 'init/environ.c' | |||
18 | --- init/environ.c 2013-10-24 13:33:05 +0000 | |||
19 | +++ init/environ.c 2014-07-16 15:55:55 +0000 | |||
20 | @@ -176,9 +176,7 @@ | |||
21 | 176 | { | 176 | { |
22 | 177 | size_t _len; | 177 | size_t _len; |
23 | 178 | size_t keylen; | 178 | size_t keylen; |
24 | 179 | size_t new_len = 0; | ||
25 | 180 | char **e; | 179 | char **e; |
26 | 181 | char **new_env; | ||
27 | 182 | 180 | ||
28 | 183 | nih_assert (env); | 181 | nih_assert (env); |
29 | 184 | nih_assert (str); | 182 | nih_assert (str); |
30 | @@ -195,10 +193,6 @@ | |||
31 | 195 | if (*len < 1) | 193 | if (*len < 1) |
32 | 196 | return NULL; | 194 | return NULL; |
33 | 197 | 195 | ||
34 | 198 | new_env = nih_str_array_new (NULL); | ||
35 | 199 | if (! new_env) | ||
36 | 200 | return NULL; | ||
37 | 201 | |||
38 | 202 | for (e = *env; e && *e; e++) { | 196 | for (e = *env; e && *e; e++) { |
39 | 203 | keylen = strcspn (*e, "="); | 197 | keylen = strcspn (*e, "="); |
40 | 204 | 198 | ||
41 | @@ -206,17 +200,21 @@ | |||
42 | 206 | * name=value pair, or a bare name), so don't copy it to | 200 | * name=value pair, or a bare name), so don't copy it to |
43 | 207 | * the new environment. | 201 | * the new environment. |
44 | 208 | */ | 202 | */ |
50 | 209 | if (! strncmp (str, *e, keylen)) | 203 | if (! strncmp (str, *e, keylen)) { |
51 | 210 | continue; | 204 | nih_unref (*e, *env); |
52 | 211 | 205 | ||
53 | 212 | if (! environ_add (&new_env, parent, &new_len, TRUE, *e)) | 206 | /* shuffle up the remaining entries */ |
54 | 213 | return NULL; | 207 | memmove (e, e + 1, (char *)(*env + *len) - (char *)e); |
55 | 208 | |||
56 | 209 | (*len)--; | ||
57 | 210 | } | ||
58 | 214 | } | 211 | } |
59 | 215 | 212 | ||
62 | 216 | *env = new_env; | 213 | /* shrink amount of memory used */ |
63 | 217 | *len = new_len; | 214 | if (! nih_realloc (*env, parent, sizeof (**env) * (*len + 1))) |
64 | 215 | return NULL; | ||
65 | 218 | 216 | ||
67 | 219 | return new_env; | 217 | return *env; |
68 | 220 | } | 218 | } |
69 | 221 | 219 | ||
70 | 222 | /** | 220 | /** |
71 | 223 | 221 | ||
72 | === modified file 'init/tests/test_environ.c' | |||
73 | --- init/tests/test_environ.c 2013-10-24 13:33:05 +0000 | |||
74 | +++ init/tests/test_environ.c 2014-07-16 15:55:55 +0000 | |||
75 | @@ -618,8 +618,10 @@ | |||
76 | 618 | void | 618 | void |
77 | 619 | test_remove (void) | 619 | test_remove (void) |
78 | 620 | { | 620 | { |
81 | 621 | char **env = NULL, **ret; | 621 | char **env = NULL; |
82 | 622 | size_t len = 0; | 622 | char *removed = NULL; |
83 | 623 | char **ret = NULL; | ||
84 | 624 | size_t len = 0; | ||
85 | 623 | 625 | ||
86 | 624 | TEST_FUNCTION ("environ_remove"); | 626 | TEST_FUNCTION ("environ_remove"); |
87 | 625 | 627 | ||
88 | @@ -688,6 +690,9 @@ | |||
89 | 688 | TEST_ALLOC_PARENT (env[0], env); | 690 | TEST_ALLOC_PARENT (env[0], env); |
90 | 689 | TEST_ALLOC_SIZE (env[0], 8); | 691 | TEST_ALLOC_SIZE (env[0], 8); |
91 | 690 | TEST_EQ_STR (env[0], "FOO=BAR"); | 692 | TEST_EQ_STR (env[0], "FOO=BAR"); |
92 | 693 | removed = env[0]; | ||
93 | 694 | TEST_FREE_TAG (removed); | ||
94 | 695 | |||
95 | 691 | TEST_EQ_P (env[1], NULL); | 696 | TEST_EQ_P (env[1], NULL); |
96 | 692 | } | 697 | } |
97 | 693 | 698 | ||
98 | @@ -695,17 +700,6 @@ | |||
99 | 695 | 700 | ||
100 | 696 | if (test_alloc_failed) { | 701 | if (test_alloc_failed) { |
101 | 697 | TEST_EQ_P (ret, NULL); | 702 | TEST_EQ_P (ret, NULL); |
102 | 698 | |||
103 | 699 | TEST_EQ (len, 1); | ||
104 | 700 | |||
105 | 701 | TEST_ALLOC_PARENT (env[0], env); | ||
106 | 702 | TEST_ALLOC_SIZE (env[0], 8); | ||
107 | 703 | |||
108 | 704 | TEST_NE_P (env[0], NULL); | ||
109 | 705 | TEST_EQ_STR (env[0], "FOO=BAR"); | ||
110 | 706 | |||
111 | 707 | TEST_EQ_P (env[1], NULL); | ||
112 | 708 | |||
113 | 709 | nih_free (env); | 703 | nih_free (env); |
114 | 710 | continue; | 704 | continue; |
115 | 711 | } | 705 | } |
116 | @@ -713,6 +707,7 @@ | |||
117 | 713 | TEST_NE_P (ret, NULL); | 707 | TEST_NE_P (ret, NULL); |
118 | 714 | TEST_EQ (len, 0); | 708 | TEST_EQ (len, 0); |
119 | 715 | TEST_EQ_P (env[0], NULL); | 709 | TEST_EQ_P (env[0], NULL); |
120 | 710 | TEST_FREE (removed); | ||
121 | 716 | 711 | ||
122 | 717 | nih_free (env); | 712 | nih_free (env); |
123 | 718 | } | 713 | } |
124 | @@ -730,6 +725,9 @@ | |||
125 | 730 | TEST_ALLOC_PARENT (env[0], env); | 725 | TEST_ALLOC_PARENT (env[0], env); |
126 | 731 | TEST_ALLOC_SIZE (env[0], 8); | 726 | TEST_ALLOC_SIZE (env[0], 8); |
127 | 732 | TEST_EQ_STR (env[0], "FOO=BAR"); | 727 | TEST_EQ_STR (env[0], "FOO=BAR"); |
128 | 728 | removed = env[0]; | ||
129 | 729 | TEST_FREE_TAG (removed); | ||
130 | 730 | |||
131 | 733 | TEST_EQ_P (env[1], NULL); | 731 | TEST_EQ_P (env[1], NULL); |
132 | 734 | } | 732 | } |
133 | 735 | 733 | ||
134 | @@ -737,17 +735,6 @@ | |||
135 | 737 | 735 | ||
136 | 738 | if (test_alloc_failed) { | 736 | if (test_alloc_failed) { |
137 | 739 | TEST_EQ_P (ret, NULL); | 737 | TEST_EQ_P (ret, NULL); |
138 | 740 | |||
139 | 741 | TEST_EQ (len, 1); | ||
140 | 742 | |||
141 | 743 | TEST_ALLOC_PARENT (env[0], env); | ||
142 | 744 | TEST_ALLOC_SIZE (env[0], 8); | ||
143 | 745 | |||
144 | 746 | TEST_NE_P (env[0], NULL); | ||
145 | 747 | TEST_EQ_STR (env[0], "FOO=BAR"); | ||
146 | 748 | |||
147 | 749 | TEST_EQ_P (env[1], NULL); | ||
148 | 750 | |||
149 | 751 | nih_free (env); | 738 | nih_free (env); |
150 | 752 | continue; | 739 | continue; |
151 | 753 | } | 740 | } |
152 | @@ -755,6 +742,7 @@ | |||
153 | 755 | TEST_NE_P (ret, NULL); | 742 | TEST_NE_P (ret, NULL); |
154 | 756 | TEST_EQ (len, 0); | 743 | TEST_EQ (len, 0); |
155 | 757 | TEST_EQ_P (env[0], NULL); | 744 | TEST_EQ_P (env[0], NULL); |
156 | 745 | TEST_FREE (removed); | ||
157 | 758 | 746 | ||
158 | 759 | nih_free (env); | 747 | nih_free (env); |
159 | 760 | } | 748 | } |
160 | @@ -781,6 +769,8 @@ | |||
161 | 781 | TEST_ALLOC_PARENT (env[0], env); | 769 | TEST_ALLOC_PARENT (env[0], env); |
162 | 782 | TEST_ALLOC_SIZE (env[0], 8); | 770 | TEST_ALLOC_SIZE (env[0], 8); |
163 | 783 | TEST_EQ_STR (env[0], "FOO=BAR"); | 771 | TEST_EQ_STR (env[0], "FOO=BAR"); |
164 | 772 | removed = env[0]; | ||
165 | 773 | TEST_FREE_TAG (removed); | ||
166 | 784 | 774 | ||
167 | 785 | TEST_ALLOC_PARENT (env[1], env); | 775 | TEST_ALLOC_PARENT (env[1], env); |
168 | 786 | TEST_ALLOC_SIZE (env[1], 8); | 776 | TEST_ALLOC_SIZE (env[1], 8); |
169 | @@ -794,18 +784,6 @@ | |||
170 | 794 | 784 | ||
171 | 795 | if (test_alloc_failed) { | 785 | if (test_alloc_failed) { |
172 | 796 | TEST_EQ_P (ret, NULL); | 786 | TEST_EQ_P (ret, NULL); |
173 | 797 | |||
174 | 798 | TEST_EQ (len, 2); | ||
175 | 799 | TEST_ALLOC_PARENT (env[0], env); | ||
176 | 800 | TEST_ALLOC_SIZE (env[0], 8); | ||
177 | 801 | TEST_EQ_STR (env[0], "FOO=BAR"); | ||
178 | 802 | |||
179 | 803 | TEST_ALLOC_PARENT (env[1], env); | ||
180 | 804 | TEST_ALLOC_SIZE (env[1], 8); | ||
181 | 805 | TEST_EQ_STR (env[1], "BAZ=QUX"); | ||
182 | 806 | |||
183 | 807 | TEST_EQ_P (env[2], NULL); | ||
184 | 808 | |||
185 | 809 | nih_free (env); | 787 | nih_free (env); |
186 | 810 | continue; | 788 | continue; |
187 | 811 | } | 789 | } |
188 | @@ -816,6 +794,7 @@ | |||
189 | 816 | TEST_ALLOC_PARENT (env[0], env); | 794 | TEST_ALLOC_PARENT (env[0], env); |
190 | 817 | TEST_ALLOC_SIZE (env[0], 8); | 795 | TEST_ALLOC_SIZE (env[0], 8); |
191 | 818 | TEST_EQ_STR (env[0], "BAZ=QUX"); | 796 | TEST_EQ_STR (env[0], "BAZ=QUX"); |
192 | 797 | TEST_FREE (removed); | ||
193 | 819 | 798 | ||
194 | 820 | TEST_EQ_P (env[1], NULL); | 799 | TEST_EQ_P (env[1], NULL); |
195 | 821 | 800 | ||
196 | @@ -852,6 +831,8 @@ | |||
197 | 852 | TEST_ALLOC_PARENT (env[0], env); | 831 | TEST_ALLOC_PARENT (env[0], env); |
198 | 853 | TEST_ALLOC_SIZE (env[0], 8); | 832 | TEST_ALLOC_SIZE (env[0], 8); |
199 | 854 | TEST_EQ_STR (env[0], "UPSTART_TEST_VARIABLE=foo"); | 833 | TEST_EQ_STR (env[0], "UPSTART_TEST_VARIABLE=foo"); |
200 | 834 | removed = env[0]; | ||
201 | 835 | TEST_FREE_TAG (removed); | ||
202 | 855 | 836 | ||
203 | 856 | TEST_ALLOC_PARENT (env[1], env); | 837 | TEST_ALLOC_PARENT (env[1], env); |
204 | 857 | TEST_ALLOC_SIZE (env[1], 8); | 838 | TEST_ALLOC_SIZE (env[1], 8); |
205 | @@ -865,18 +846,6 @@ | |||
206 | 865 | 846 | ||
207 | 866 | if (test_alloc_failed) { | 847 | if (test_alloc_failed) { |
208 | 867 | TEST_EQ_P (ret, NULL); | 848 | TEST_EQ_P (ret, NULL); |
209 | 868 | |||
210 | 869 | TEST_EQ (len, 2); | ||
211 | 870 | TEST_ALLOC_PARENT (env[0], env); | ||
212 | 871 | TEST_ALLOC_SIZE (env[0], 8); | ||
213 | 872 | TEST_EQ_STR (env[0], "UPSTART_TEST_VARIABLE=foo"); | ||
214 | 873 | |||
215 | 874 | TEST_ALLOC_PARENT (env[1], env); | ||
216 | 875 | TEST_ALLOC_SIZE (env[1], 8); | ||
217 | 876 | TEST_EQ_STR (env[1], "BAZ=QUX"); | ||
218 | 877 | |||
219 | 878 | TEST_EQ_P (env[2], NULL); | ||
220 | 879 | |||
221 | 880 | nih_free (env); | 849 | nih_free (env); |
222 | 881 | continue; | 850 | continue; |
223 | 882 | } | 851 | } |
224 | @@ -887,6 +856,7 @@ | |||
225 | 887 | TEST_ALLOC_PARENT (env[0], env); | 856 | TEST_ALLOC_PARENT (env[0], env); |
226 | 888 | TEST_ALLOC_SIZE (env[0], 8); | 857 | TEST_ALLOC_SIZE (env[0], 8); |
227 | 889 | TEST_EQ_STR (env[0], "BAZ=QUX"); | 858 | TEST_EQ_STR (env[0], "BAZ=QUX"); |
228 | 859 | TEST_FREE (removed); | ||
229 | 890 | 860 | ||
230 | 891 | TEST_EQ_P (env[1], NULL); | 861 | TEST_EQ_P (env[1], NULL); |
231 | 892 | 862 | ||
232 | @@ -921,6 +891,8 @@ | |||
233 | 921 | TEST_ALLOC_PARENT (env[1], env); | 891 | TEST_ALLOC_PARENT (env[1], env); |
234 | 922 | TEST_ALLOC_SIZE (env[1], 8); | 892 | TEST_ALLOC_SIZE (env[1], 8); |
235 | 923 | TEST_EQ_STR (env[1], "BAZ=QUX"); | 893 | TEST_EQ_STR (env[1], "BAZ=QUX"); |
236 | 894 | removed = env[1]; | ||
237 | 895 | TEST_FREE_TAG (removed); | ||
238 | 924 | 896 | ||
239 | 925 | TEST_EQ_P (env[2], NULL); | 897 | TEST_EQ_P (env[2], NULL); |
240 | 926 | } | 898 | } |
241 | @@ -930,18 +902,6 @@ | |||
242 | 930 | 902 | ||
243 | 931 | if (test_alloc_failed) { | 903 | if (test_alloc_failed) { |
244 | 932 | TEST_EQ_P (ret, NULL); | 904 | TEST_EQ_P (ret, NULL); |
245 | 933 | |||
246 | 934 | TEST_EQ (len, 2); | ||
247 | 935 | TEST_ALLOC_PARENT (env[0], env); | ||
248 | 936 | TEST_ALLOC_SIZE (env[0], 8); | ||
249 | 937 | TEST_EQ_STR (env[0], "FOO=BAR"); | ||
250 | 938 | |||
251 | 939 | TEST_ALLOC_PARENT (env[1], env); | ||
252 | 940 | TEST_ALLOC_SIZE (env[1], 8); | ||
253 | 941 | TEST_EQ_STR (env[1], "BAZ=QUX"); | ||
254 | 942 | |||
255 | 943 | TEST_EQ_P (env[2], NULL); | ||
256 | 944 | |||
257 | 945 | nih_free (env); | 905 | nih_free (env); |
258 | 946 | continue; | 906 | continue; |
259 | 947 | } | 907 | } |
260 | @@ -954,6 +914,7 @@ | |||
261 | 954 | TEST_EQ_STR (env[0], "FOO=BAR"); | 914 | TEST_EQ_STR (env[0], "FOO=BAR"); |
262 | 955 | 915 | ||
263 | 956 | TEST_EQ_P (env[1], NULL); | 916 | TEST_EQ_P (env[1], NULL); |
264 | 917 | TEST_FREE (removed); | ||
265 | 957 | 918 | ||
266 | 958 | nih_free (env); | 919 | nih_free (env); |
267 | 959 | } | 920 | } |
268 | @@ -991,6 +952,9 @@ | |||
269 | 991 | /* Should have been expanded */ | 952 | /* Should have been expanded */ |
270 | 992 | TEST_EQ_STR (env[1], "UPSTART_TEST_VARIABLE=foo"); | 953 | TEST_EQ_STR (env[1], "UPSTART_TEST_VARIABLE=foo"); |
271 | 993 | 954 | ||
272 | 955 | removed = env[1]; | ||
273 | 956 | TEST_FREE_TAG (removed); | ||
274 | 957 | |||
275 | 994 | TEST_EQ_P (env[2], NULL); | 958 | TEST_EQ_P (env[2], NULL); |
276 | 995 | } | 959 | } |
277 | 996 | 960 | ||
278 | @@ -999,18 +963,6 @@ | |||
279 | 999 | 963 | ||
280 | 1000 | if (test_alloc_failed) { | 964 | if (test_alloc_failed) { |
281 | 1001 | TEST_EQ_P (ret, NULL); | 965 | TEST_EQ_P (ret, NULL); |
282 | 1002 | |||
283 | 1003 | TEST_EQ (len, 2); | ||
284 | 1004 | TEST_ALLOC_PARENT (env[0], env); | ||
285 | 1005 | TEST_ALLOC_SIZE (env[0], 8); | ||
286 | 1006 | TEST_EQ_STR (env[0], "FOO=BAR"); | ||
287 | 1007 | |||
288 | 1008 | TEST_ALLOC_PARENT (env[1], env); | ||
289 | 1009 | TEST_ALLOC_SIZE (env[1], 8); | ||
290 | 1010 | TEST_EQ_STR (env[1], "UPSTART_TEST_VARIABLE=foo"); | ||
291 | 1011 | |||
292 | 1012 | TEST_EQ_P (env[2], NULL); | ||
293 | 1013 | |||
294 | 1014 | nih_free (env); | 966 | nih_free (env); |
295 | 1015 | continue; | 967 | continue; |
296 | 1016 | } | 968 | } |
297 | @@ -1023,6 +975,7 @@ | |||
298 | 1023 | TEST_EQ_STR (env[0], "FOO=BAR"); | 975 | TEST_EQ_STR (env[0], "FOO=BAR"); |
299 | 1024 | 976 | ||
300 | 1025 | TEST_EQ_P (env[1], NULL); | 977 | TEST_EQ_P (env[1], NULL); |
301 | 978 | TEST_FREE (removed); | ||
302 | 1026 | 979 | ||
303 | 1027 | nih_free (env); | 980 | nih_free (env); |
304 | 1028 | } | 981 | } |
See inline comment about memove call.