diff options
author | Stefan Ghinea <stefan.ghinea@windriver.com> | 2020-03-12 11:23:22 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2020-03-19 09:57:51 +0000 |
commit | d08c1b7e9c5044e330aa9aa552e34ce7f8d48af2 (patch) | |
tree | 940b0d9f1c3ec4799363028a3db5539de9821d33 /meta/recipes-support | |
parent | 61210237a7d304a0e2eeef9f9f224a9cf337cdb9 (diff) | |
download | poky-d08c1b7e9c5044e330aa9aa552e34ce7f8d48af2.tar.gz |
aspell: CVE-2019-20433
libaspell.a in GNU Aspell before 0.60.8 has a buffer over-read for a string
ending with a single '\0' byte, if the encoding is set to ucs-2 or ucs-4
outside of the application, as demonstrated by the ASPELL_CONF environment
variable.
References:
https://nvd.nist.gov/vuln/detail/CVE-2019-20433
Upstream patches:
https://github.com/GNUAspell/aspell/commit/de29341638833ba7717bd6b5e6850998454b044b
https://github.com/GNUAspell/aspell/commit/cefd447e5528b08bb0cd6656bc52b4255692cefc
(From OE-Core rev: 07dc85604baf696cccf784c909dbad67275ad7b3)
Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-support')
3 files changed, 1069 insertions, 0 deletions
diff --git a/meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch new file mode 100644 index 0000000000..fd68461e32 --- /dev/null +++ b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0001.patch | |||
@@ -0,0 +1,999 @@ | |||
1 | From de29341638833ba7717bd6b5e6850998454b044b Mon Sep 17 00:00:00 2001 | ||
2 | From: Kevin Atkinson <kevina@gnu.org> | ||
3 | Date: Sat, 17 Aug 2019 17:06:53 -0400 | ||
4 | Subject: [PATCH 1/2] Don't allow null-terminated UCS-2/4 strings using the | ||
5 | original API. | ||
6 | |||
7 | Detect if the encoding is UCS-2/4 and the length is -1 in affected API | ||
8 | functions and refuse to convert the string. If the string ends up | ||
9 | being converted somehow, abort with an error message in DecodeDirect | ||
10 | and ConvDirect. To convert a null terminated string in | ||
11 | Decode/ConvDirect, a negative number corresponding to the width of the | ||
12 | underlying character type for the encoding is expected; for example, | ||
13 | if the encoding is "ucs-2" then a the size is expected to be -2. | ||
14 | |||
15 | Also fix a 1-3 byte over-read in DecodeDirect when reading UCS-2/4 | ||
16 | strings when a size is provided (found by OSS-Fuzz). | ||
17 | |||
18 | Also fix a bug in DecodeDirect that caused DocumentChecker to return | ||
19 | the wrong offsets when working with UCS-2/4 strings. | ||
20 | |||
21 | CVE: CVE-2019-20433 | ||
22 | Upstream-Status: Backport [https://github.com/GNUAspell/aspell/commit/de29341638833ba7717bd6b5e6850998454b044b] | ||
23 | |||
24 | [SG: - adjusted context | ||
25 | - discarded test changes as test framework is not available | ||
26 | - discarded manual entry changes for features that aren't backported] | ||
27 | Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com> | ||
28 | --- | ||
29 | auto/MkSrc/CcHelper.pm | 99 ++++++++++++++++++++++++++++++++++--- | ||
30 | auto/MkSrc/Create.pm | 5 +- | ||
31 | auto/MkSrc/Info.pm | 5 +- | ||
32 | auto/MkSrc/ProcCc.pm | 24 +++++---- | ||
33 | auto/MkSrc/ProcImpl.pm | 57 +++++++++++++++------ | ||
34 | auto/MkSrc/Read.pm | 4 +- | ||
35 | auto/mk-src.in | 44 +++++++++++++++-- | ||
36 | common/convert.cpp | 39 ++++++++++++--- | ||
37 | common/convert.hpp | 38 +++++++++++++- | ||
38 | common/document_checker.cpp | 17 ++++++- | ||
39 | common/document_checker.hpp | 1 + | ||
40 | common/version.cpp | 15 ++++-- | ||
41 | configure.ac | 8 +++ | ||
42 | manual/aspell.texi | 58 ++++++++++++++++------ | ||
43 | manual/readme.texi | 70 +++++++++++++++++++++----- | ||
44 | 15 files changed, 409 insertions(+), 75 deletions(-) | ||
45 | |||
46 | diff --git a/auto/MkSrc/CcHelper.pm b/auto/MkSrc/CcHelper.pm | ||
47 | index f2de991..0044335 100644 | ||
48 | --- a/auto/MkSrc/CcHelper.pm | ||
49 | +++ b/auto/MkSrc/CcHelper.pm | ||
50 | @@ -10,8 +10,8 @@ BEGIN { | ||
51 | use Exporter; | ||
52 | our @ISA = qw(Exporter); | ||
53 | our @EXPORT = qw(to_c_return_type c_error_cond | ||
54 | - to_type_name make_desc make_func call_func | ||
55 | - make_c_method call_c_method form_c_method | ||
56 | + to_type_name make_desc make_func call_func get_c_func_name | ||
57 | + make_c_method make_wide_macro call_c_method form_c_method | ||
58 | make_cxx_method); | ||
59 | } | ||
60 | |||
61 | @@ -90,6 +90,69 @@ sub make_func ( $ \@ $ ; \% ) { | ||
62 | ')')); | ||
63 | } | ||
64 | |||
65 | +=item make_wide_version NAME @TYPES PARMS ; %ACCUM | ||
66 | + | ||
67 | +Creates the wide character version of the function if needed | ||
68 | + | ||
69 | +=cut | ||
70 | + | ||
71 | +sub make_wide_version ( $ \@ $ ; \% ) { | ||
72 | + my ($name, $d, $p, $accum) = @_; | ||
73 | + my @d = @$d; | ||
74 | + shift @d; | ||
75 | + return '' unless grep {$_->{type} eq 'encoded string'} @d; | ||
76 | + $accum->{sys_headers}{'stddef.h'} = true; | ||
77 | + $accum->{suffix}[5] = <<'---'; | ||
78 | + | ||
79 | +/******************* private implemantion details *********************/ | ||
80 | + | ||
81 | +#ifdef __cplusplus | ||
82 | +# define aspell_cast_(type, expr) (static_cast<type>(expr)) | ||
83 | +# define aspell_cast_from_wide_(str) (static_cast<const void *>(str)) | ||
84 | +#else | ||
85 | +# define aspell_cast_(type, expr) ((type)(expr)) | ||
86 | +# define aspell_cast_from_wide_(str) ((const char *)(str)) | ||
87 | +#endif | ||
88 | +--- | ||
89 | + my @parms = map {$_->{type} eq 'encoded string' | ||
90 | + ? ($_->{name}, $_->{name}.'_size') | ||
91 | + : $_->{name}} @d; | ||
92 | + $name = to_lower $name; | ||
93 | + $accum->{suffix}[0] = <<'---'; | ||
94 | +/**********************************************************************/ | ||
95 | + | ||
96 | +#ifdef ASPELL_ENCODE_SETTING_SECURE | ||
97 | +--- | ||
98 | + $accum->{suffix}[2] = "#endif\n"; | ||
99 | + my @args = map {$_->{type} eq 'encoded string' | ||
100 | + ? ($_->{name}, "$_->{name}_size", '-1') | ||
101 | + : $_->{name}} @d; | ||
102 | + $accum->{suffix}[1] .= | ||
103 | + (join '', | ||
104 | + "#define $name", | ||
105 | + '(', join(', ', @parms), ')', | ||
106 | + "\\\n ", | ||
107 | + $name, '_wide', | ||
108 | + '(', join(', ', @args), ')', | ||
109 | + "\n"); | ||
110 | + @args = map {$_->{type} eq 'encoded string' | ||
111 | + ? ("aspell_cast_from_wide_($_->{name})", | ||
112 | + "$_->{name}_size*aspell_cast_(int,sizeof(*($_->{name})))", | ||
113 | + "sizeof(*($_->{name}))") | ||
114 | + : $_->{name}} @d; | ||
115 | + return (join '', | ||
116 | + "\n", | ||
117 | + "/* version of $name that is safe to use with (null terminated) wide characters */\n", | ||
118 | + '#define ', | ||
119 | + $name, '_w', | ||
120 | + '(', join(', ', @parms), ')', | ||
121 | + "\\\n ", | ||
122 | + $name, '_wide', | ||
123 | + '(', join(', ', @args), ')', | ||
124 | + "\n"); | ||
125 | +} | ||
126 | + | ||
127 | + | ||
128 | =item call_func NAME @TYPES PARMS ; %ACCUM | ||
129 | |||
130 | Return a string to call a func. Will prefix the function with return | ||
131 | @@ -103,7 +166,6 @@ Parms can be any of: | ||
132 | |||
133 | sub call_func ( $ \@ $ ; \% ) { | ||
134 | my ($name, $d, $p, $accum) = @_; | ||
135 | - $accum = {} unless defined $accum; | ||
136 | my @d = @$d; | ||
137 | my $func_ret = to_type_name(shift @d, {%$p,pos=>'return'}, %$accum); | ||
138 | return (join '', | ||
139 | @@ -148,8 +210,14 @@ sub to_type_name ( $ $ ; \% ) { | ||
140 | my $name = $t->{name}; | ||
141 | my $type = $t->{type}; | ||
142 | |||
143 | - return ( (to_type_name {%$d, type=>'string'}, $p, %$accum) , | ||
144 | - (to_type_name {%$d, type=>'int', name=>"$d->{name}_size"}, $p, %$accum) ) | ||
145 | + if ($name eq 'encoded string' && $is_cc && $pos eq 'parm') { | ||
146 | + my @types = ((to_type_name {%$d, type=>($p->{wide}?'const void pointer':'string')}, $p, %$accum), | ||
147 | + (to_type_name {%$d, type=>'int', name=>"$d->{name}_size"}, $p, %$accum)); | ||
148 | + push @types, (to_type_name {%$d, type=>'int', name=>"$d->{name}_type_width"}, $p, %$accum) if $p->{wide}; | ||
149 | + return @types; | ||
150 | + } | ||
151 | + return ( (to_type_name {%$d, type=>($p->{wide}?'const void pointer':'string')}, $p, %$accum) , | ||
152 | + (to_type_name {%$d, type=>'int', name=>"$d->{name}_size"}, $p, %$accum) ) | ||
153 | if $name eq 'encoded string' && $is_cc && $pos eq 'parm'; | ||
154 | |||
155 | my $str; | ||
156 | @@ -174,7 +242,7 @@ sub to_type_name ( $ $ ; \% ) { | ||
157 | $str .= "String"; | ||
158 | } | ||
159 | } elsif ($name eq 'encoded string') { | ||
160 | - $str .= "const char *"; | ||
161 | + $str .= $p->{wide} ? "const void *" : "const char *"; | ||
162 | } elsif ($name eq '') { | ||
163 | $str .= "void"; | ||
164 | } elsif ($name eq 'bool' && $is_cc) { | ||
165 | @@ -186,7 +254,7 @@ sub to_type_name ( $ $ ; \% ) { | ||
166 | if ($t->{pointer}) { | ||
167 | $accum->{types}->{$name} = $t; | ||
168 | } else { | ||
169 | - $accum->{headers}->{$t->{created_in}} = true; | ||
170 | + $accum->{headers}->{$t->{created_in}} = true unless $mode eq 'cc'; | ||
171 | } | ||
172 | $str .= "$c_type Aspell" if $mode eq 'cc'; | ||
173 | $str .= to_mixed($name); | ||
174 | @@ -214,6 +282,7 @@ sub to_type_name ( $ $ ; \% ) { | ||
175 | return $str; | ||
176 | } | ||
177 | |||
178 | + | ||
179 | =item make_desc DESC ; LEVEL | ||
180 | |||
181 | Make a C comment out of DESC optionally indenting it LEVEL spaces. | ||
182 | @@ -286,6 +355,7 @@ sub form_c_method ($ $ $ ; \% ) | ||
183 | } else { | ||
184 | $func = "aspell $class $name"; | ||
185 | } | ||
186 | + $func .= " wide" if $p->{wide}; | ||
187 | if (exists $d->{'const'}) { | ||
188 | splice @data, 1, 0, {type => "const $class", name=> $this_name}; | ||
189 | } else { | ||
190 | @@ -306,6 +376,21 @@ sub make_c_method ($ $ $ ; \%) | ||
191 | return &make_func(@ret); | ||
192 | } | ||
193 | |||
194 | +sub get_c_func_name ($ $ $) | ||
195 | +{ | ||
196 | + my @ret = &form_c_method(@_); | ||
197 | + return undef unless @ret > 0; | ||
198 | + return to_lower $ret[0]; | ||
199 | +} | ||
200 | + | ||
201 | +sub make_wide_macro ($ $ $ ; \%) | ||
202 | +{ | ||
203 | + my @ret = &form_c_method(@_); | ||
204 | + return undef unless @ret > 0; | ||
205 | + my $str = &make_wide_version(@ret); | ||
206 | + return $str; | ||
207 | +} | ||
208 | + | ||
209 | sub call_c_method ($ $ $ ; \%) | ||
210 | { | ||
211 | my @ret = &form_c_method(@_); | ||
212 | diff --git a/auto/MkSrc/Create.pm b/auto/MkSrc/Create.pm | ||
213 | index d39b60e..630ede5 100644 | ||
214 | --- a/auto/MkSrc/Create.pm | ||
215 | +++ b/auto/MkSrc/Create.pm | ||
216 | @@ -77,8 +77,10 @@ sub create_cc_file ( % ) { | ||
217 | $file .= "#include \"aspell.h\"\n" if $p{type} eq 'cxx'; | ||
218 | $file .= "#include \"settings.h\"\n" if $p{type} eq 'native_impl' && $p{name} eq 'errors'; | ||
219 | $file .= "#include \"gettext.h\"\n" if $p{type} eq 'native_impl' && $p{name} eq 'errors'; | ||
220 | + $file .= cmap {"#include <$_>\n"} sort keys %{$accum{sys_headers}}; | ||
221 | $file .= cmap {"#include \"".to_lower($_).".hpp\"\n"} sort keys %{$accum{headers}}; | ||
222 | - $file .= "#ifdef __cplusplus\nextern \"C\" {\n#endif\n" if $p{header} && !$p{cxx}; | ||
223 | + $file .= "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" if $p{header} && !$p{cxx}; | ||
224 | + $file .= join('', grep {defined $_} @{$accum{prefix}}); | ||
225 | $file .= "\nnamespace $p{namespace} {\n\n" if $p{cxx}; | ||
226 | if (defined $info{forward}{proc}{$p{type}}) { | ||
227 | my @types = sort {$a->{name} cmp $b->{name}} (values %{$accum{types}}); | ||
228 | @@ -86,6 +88,7 @@ sub create_cc_file ( % ) { | ||
229 | } | ||
230 | $file .= "\n"; | ||
231 | $file .= $body; | ||
232 | + $file .= join('', grep {defined $_} @{$accum{suffix}}); | ||
233 | $file .= "\n\n}\n\n" if $p{cxx}; | ||
234 | $file .= "#ifdef __cplusplus\n}\n#endif\n" if $p{header} && !$p{cxx}; | ||
235 | $file .= "#endif /* $hm */\n" if $p{header}; | ||
236 | diff --git a/auto/MkSrc/Info.pm b/auto/MkSrc/Info.pm | ||
237 | index c644028..ace8e21 100644 | ||
238 | --- a/auto/MkSrc/Info.pm | ||
239 | +++ b/auto/MkSrc/Info.pm | ||
240 | @@ -60,6 +60,7 @@ each proc sub should take the following argv | ||
241 | the object from which it is a member of | ||
242 | no native: do not attempt to create a native implementation | ||
243 | treat as object: treat as a object rather than a pointer | ||
244 | + no conv: do not converted an encoded string | ||
245 | |||
246 | The %info structure is initialized as follows: | ||
247 | |||
248 | @@ -104,8 +105,8 @@ The %info structure is initialized as follows: | ||
249 | errors => {}, # possible errors | ||
250 | method => { | ||
251 | # A class method | ||
252 | - options => ['desc', 'posib err', 'c func', 'const', | ||
253 | - 'c only', 'c impl', 'cxx impl'], | ||
254 | + options => ['desc', 'posib err', 'c func', 'const', 'no conv', 'on conv error', | ||
255 | + 'c only', 'c impl', 'cxx impl', 'cc extra'], | ||
256 | groups => undef}, | ||
257 | constructor => { | ||
258 | # A class constructor | ||
259 | diff --git a/auto/MkSrc/ProcCc.pm b/auto/MkSrc/ProcCc.pm | ||
260 | index 47c4338..98cc435 100644 | ||
261 | --- a/auto/MkSrc/ProcCc.pm | ||
262 | +++ b/auto/MkSrc/ProcCc.pm | ||
263 | @@ -23,7 +23,7 @@ use MkSrc::Info; | ||
264 | sub make_c_object ( $ @ ); | ||
265 | |||
266 | $info{group}{proc}{cc} = sub { | ||
267 | - my ($data) = @_; | ||
268 | + my ($data,@rest) = @_; | ||
269 | my $ret; | ||
270 | my $stars = (70 - length $data->{name})/2; | ||
271 | $ret .= "/"; | ||
272 | @@ -33,14 +33,14 @@ $info{group}{proc}{cc} = sub { | ||
273 | $ret .= "/\n"; | ||
274 | foreach my $d (@{$data->{data}}) { | ||
275 | $ret .= "\n\n"; | ||
276 | - $ret .= $info{$d->{type}}{proc}{cc}->($d); | ||
277 | + $ret .= $info{$d->{type}}{proc}{cc}->($d,@rest); | ||
278 | } | ||
279 | $ret .= "\n\n"; | ||
280 | return $ret; | ||
281 | }; | ||
282 | |||
283 | $info{enum}{proc}{cc} = sub { | ||
284 | - my ($d) = @_; | ||
285 | + my ($d,@rest) = @_; | ||
286 | my $n = "Aspell".to_mixed($d->{name}); | ||
287 | return ("\n". | ||
288 | make_desc($d->{desc}). | ||
289 | @@ -58,21 +58,26 @@ $info{struct}{proc}{cc} = sub { | ||
290 | }; | ||
291 | |||
292 | $info{union}{proc}{cc} = sub { | ||
293 | - return make_c_object "union", $_[0]; | ||
294 | + return make_c_object "union", @_; | ||
295 | }; | ||
296 | |||
297 | $info{class}{proc}{cc} = sub { | ||
298 | - my ($d) = @_; | ||
299 | + my ($d,$accum) = @_; | ||
300 | my $class = $d->{name}; | ||
301 | my $classname = "Aspell".to_mixed($class); | ||
302 | my $ret = ""; | ||
303 | $ret .= "typedef struct $classname $classname;\n\n"; | ||
304 | foreach (@{$d->{data}}) { | ||
305 | - my $s = make_c_method($class, $_, {mode=>'cc'}); | ||
306 | + my $s = make_c_method($class, $_, {mode=>'cc'}, %$accum); | ||
307 | next unless defined $s; | ||
308 | $ret .= "\n"; | ||
309 | $ret .= make_desc($_->{desc}); | ||
310 | - $ret .= make_c_method($class, $_, {mode=>'cc'}).";\n"; | ||
311 | + $ret .= make_c_method($class, $_, {mode=>'cc'}, %$accum).";\n"; | ||
312 | + if (grep {$_->{type} eq 'encoded string'} @{$_->{data}}) { | ||
313 | + $ret .= make_c_method($class, $_, {mode=>'cc', wide=>true}, %$accum).";\n"; | ||
314 | + $ret .= make_wide_macro($class, $_, {mode=>'cc'}, %$accum); | ||
315 | + } | ||
316 | + $ret .= "\n".$_->{'cc extra'}."\n" if defined $_->{'cc extra'}; | ||
317 | } | ||
318 | $ret .= "\n"; | ||
319 | return $ret; | ||
320 | @@ -105,7 +110,8 @@ $info{errors}{proc}{cc} = sub { | ||
321 | }; | ||
322 | |||
323 | sub make_c_object ( $ @ ) { | ||
324 | - my ($t, $d) = @_; | ||
325 | + my ($t, $d, $accum) = @_; | ||
326 | + $accum = {} unless defined $accum; | ||
327 | my $struct; | ||
328 | $struct .= "Aspell"; | ||
329 | $struct .= to_mixed($d->{name}); | ||
330 | @@ -120,7 +126,7 @@ sub make_c_object ( $ @ ) { | ||
331 | "\n};\n"), | ||
332 | "typedef $t $struct $struct;", | ||
333 | join ("\n", | ||
334 | - map {make_c_method($d->{name}, $_, {mode=>'cc'}).";"} | ||
335 | + map {make_c_method($d->{name}, $_, {mode=>'cc'}, %$accum).";"} | ||
336 | grep {$_->{type} eq 'method'} | ||
337 | @{$d->{data}}) | ||
338 | )."\n"; | ||
339 | diff --git a/auto/MkSrc/ProcImpl.pm b/auto/MkSrc/ProcImpl.pm | ||
340 | index b8628fd..3d0f220 100644 | ||
341 | --- a/auto/MkSrc/ProcImpl.pm | ||
342 | +++ b/auto/MkSrc/ProcImpl.pm | ||
343 | @@ -45,10 +45,13 @@ $info{class}{proc}{impl} = sub { | ||
344 | foreach (grep {$_ ne ''} split /\s*,\s*/, $data->{'c impl headers'}) { | ||
345 | $accum->{headers}{$_} = true; | ||
346 | } | ||
347 | - foreach my $d (@{$data->{data}}) { | ||
348 | + my @d = @{$data->{data}}; | ||
349 | + while (@d) { | ||
350 | + my $d = shift @d; | ||
351 | + my $need_wide = false; | ||
352 | next unless one_of $d->{type}, qw(method constructor destructor); | ||
353 | my @parms = @{$d->{data}} if exists $d->{data}; | ||
354 | - my $m = make_c_method $data->{name}, $d, {mode=>'cc_cxx', use_name=>true}, %$accum; | ||
355 | + my $m = make_c_method $data->{name}, $d, {mode=>'cc_cxx', use_name=>true, wide=>$d->{wide}}, %$accum; | ||
356 | next unless defined $m; | ||
357 | $ret .= "extern \"C\" $m\n"; | ||
358 | $ret .= "{\n"; | ||
359 | @@ -57,24 +60,49 @@ $info{class}{proc}{impl} = sub { | ||
360 | } else { | ||
361 | if ($d->{type} eq 'method') { | ||
362 | my $ret_type = shift @parms; | ||
363 | - my $ret_native = to_type_name $ret_type, {mode=>'native_no_err', pos=>'return'}, %$accum; | ||
364 | + my $ret_native = to_type_name $ret_type, {mode=>'native_no_err', pos=>'return', wide=>$d->{wide}}, %$accum; | ||
365 | my $snum = 0; | ||
366 | + my $call_fun = $d->{name}; | ||
367 | + my @call_parms; | ||
368 | foreach (@parms) { | ||
369 | my $n = to_lower($_->{name}); | ||
370 | - if ($_->{type} eq 'encoded string') { | ||
371 | - $accum->{headers}{'mutable string'} = true; | ||
372 | - $accum->{headers}{'convert'} = true; | ||
373 | - $ret .= " ths->temp_str_$snum.clear();\n"; | ||
374 | - $ret .= " ths->to_internal_->convert($n, ${n}_size, ths->temp_str_$snum);\n"; | ||
375 | - $ret .= " unsigned int s$snum = ths->temp_str_$snum.size();\n"; | ||
376 | - $_ = "MutableString(ths->temp_str_$snum.mstr(), s$snum)"; | ||
377 | - $snum++; | ||
378 | + if ($_->{type} eq 'encoded string' && !exists($d->{'no conv'})) { | ||
379 | + $need_wide = true unless $d->{wide}; | ||
380 | + die unless exists $d->{'posib err'}; | ||
381 | + $accum->{headers}{'mutable string'} = true; | ||
382 | + $accum->{headers}{'convert'} = true; | ||
383 | + my $name = get_c_func_name $data->{name}, $d, {mode=>'cc_cxx', use_name=>true, wide=>$d->{wide}}; | ||
384 | + $ret .= " ths->temp_str_$snum.clear();\n"; | ||
385 | + if ($d->{wide}) { | ||
386 | + $ret .= " ${n}_size = get_correct_size(\"$name\", ths->to_internal_->in_type_width(), ${n}_size, ${n}_type_width);\n"; | ||
387 | + } else { | ||
388 | + $ret .= " PosibErr<int> ${n}_fixed_size = get_correct_size(\"$name\", ths->to_internal_->in_type_width(), ${n}_size);\n"; | ||
389 | + if (exists($d->{'on conv error'})) { | ||
390 | + $ret .= " if (${n}_fixed_size.get_err()) {\n"; | ||
391 | + $ret .= " ".$d->{'on conv error'}."\n"; | ||
392 | + $ret .= " } else {\n"; | ||
393 | + $ret .= " ${n}_size = ${n}_fixed_size;\n"; | ||
394 | + $ret .= " }\n"; | ||
395 | + } else { | ||
396 | + $ret .= " ths->err_.reset(${n}_fixed_size.release_err());\n"; | ||
397 | + $ret .= " if (ths->err_ != 0) return ".(c_error_cond $ret_type).";\n"; | ||
398 | + } | ||
399 | + } | ||
400 | + $ret .= " ths->to_internal_->convert($n, ${n}_size, ths->temp_str_$snum);\n"; | ||
401 | + $ret .= " unsigned int s$snum = ths->temp_str_$snum.size();\n"; | ||
402 | + push @call_parms, "MutableString(ths->temp_str_$snum.mstr(), s$snum)"; | ||
403 | + $snum++; | ||
404 | + } elsif ($_->{type} eq 'encoded string') { | ||
405 | + $need_wide = true unless $d->{wide}; | ||
406 | + push @call_parms, $n, "${n}_size"; | ||
407 | + push @call_parms, "${n}_type_width" if $d->{wide}; | ||
408 | + $call_fun .= " wide" if $d->{wide}; | ||
409 | } else { | ||
410 | - $_ = $n; | ||
411 | + push @call_parms, $n; | ||
412 | } | ||
413 | } | ||
414 | - my $parms = '('.(join ', ', @parms).')'; | ||
415 | - my $exp = "ths->".to_lower($d->{name})."$parms"; | ||
416 | + my $parms = '('.(join ', ', @call_parms).')'; | ||
417 | + my $exp = "ths->".to_lower($call_fun)."$parms"; | ||
418 | if (exists $d->{'posib err'}) { | ||
419 | $accum->{headers}{'posib err'} = true; | ||
420 | $ret .= " PosibErr<$ret_native> ret = $exp;\n"; | ||
421 | @@ -118,6 +146,7 @@ $info{class}{proc}{impl} = sub { | ||
422 | } | ||
423 | } | ||
424 | $ret .= "}\n\n"; | ||
425 | + unshift @d,{%$d, wide=>true} if $need_wide; | ||
426 | } | ||
427 | return $ret; | ||
428 | }; | ||
429 | diff --git a/auto/MkSrc/Read.pm b/auto/MkSrc/Read.pm | ||
430 | index 4b3d1d0..4bf640e 100644 | ||
431 | --- a/auto/MkSrc/Read.pm | ||
432 | +++ b/auto/MkSrc/Read.pm | ||
433 | @@ -88,13 +88,13 @@ sub advance ( ) { | ||
434 | $in_pod = $1 if $line =~ /^\=(\w+)/; | ||
435 | $line = '' if $in_pod; | ||
436 | $in_pod = undef if $in_pod && $in_pod eq 'cut'; | ||
437 | - $line =~ s/\#.*$//; | ||
438 | + $line =~ s/(?<!\\)\#.*$//; | ||
439 | $line =~ s/^(\t*)//; | ||
440 | $level = $base_level + length($1); | ||
441 | $line =~ s/\s*$//; | ||
442 | ++$base_level if $line =~ s/^\{$//; | ||
443 | --$base_level if $line =~ s/^\}$//; | ||
444 | - $line =~ s/\\([{}])/$1/g; | ||
445 | + $line =~ s/\\([{}#\\])/$1/g; | ||
446 | } while ($line eq ''); | ||
447 | #print "$level:$line\n"; | ||
448 | } | ||
449 | diff --git a/auto/mk-src.in b/auto/mk-src.in | ||
450 | index 0e7833a..eb3353f 100644 | ||
451 | --- a/auto/mk-src.in | ||
452 | +++ b/auto/mk-src.in | ||
453 | @@ -608,6 +608,7 @@ errors: | ||
454 | invalid expression | ||
455 | mesg => "%expression" is not a valid regular expression. | ||
456 | parms => expression | ||
457 | + | ||
458 | } | ||
459 | group: speller | ||
460 | { | ||
461 | @@ -650,6 +651,7 @@ class: speller | ||
462 | posib err | ||
463 | desc => Returns 0 if it is not in the dictionary, | ||
464 | 1 if it is, or -1 on error. | ||
465 | + on conv error => return 0; | ||
466 | / | ||
467 | bool | ||
468 | encoded string: word | ||
469 | @@ -715,6 +717,8 @@ class: speller | ||
470 | desc => Return NULL on error. | ||
471 | The word list returned by suggest is only | ||
472 | valid until the next call to suggest. | ||
473 | + on conv error => | ||
474 | + word = NULL; word_size = 0; | ||
475 | / | ||
476 | const word list | ||
477 | encoded string: word | ||
478 | @@ -840,7 +844,6 @@ class: document checker | ||
479 | void | ||
480 | |||
481 | method: process | ||
482 | - | ||
483 | desc => Process a string. | ||
484 | The string passed in should only be split on | ||
485 | white space characters. Furthermore, between | ||
486 | @@ -849,10 +852,10 @@ class: document checker | ||
487 | in the document. Passing in strings out of | ||
488 | order, skipping strings or passing them in | ||
489 | more than once may lead to undefined results. | ||
490 | + no conv | ||
491 | / | ||
492 | void | ||
493 | - string: str | ||
494 | - int: size | ||
495 | + encoded string: str | ||
496 | |||
497 | method: next misspelling | ||
498 | |||
499 | @@ -860,9 +863,23 @@ class: document checker | ||
500 | processed string. If there are no more | ||
501 | misspelled words, then token.word will be | ||
502 | NULL and token.size will be 0 | ||
503 | + cc extra => | ||
504 | + \#define aspell_document_checker_next_misspelling_w(type, ths) \\ | ||
505 | + aspell_document_checker_next_misspelling_adj(ths, sizeof(type)) | ||
506 | / | ||
507 | token object | ||
508 | |||
509 | + method: next misspelling adj | ||
510 | + desc => internal: do not use | ||
511 | + c impl => | ||
512 | + Token res = ths->next_misspelling(); | ||
513 | + res.offset /= type_width; | ||
514 | + res.len /= type_width; | ||
515 | + return res; | ||
516 | + / | ||
517 | + token object | ||
518 | + int: type_width | ||
519 | + | ||
520 | method: filter | ||
521 | |||
522 | desc => Returns the underlying filter class. | ||
523 | @@ -922,9 +939,30 @@ class: string enumeration | ||
524 | ths->from_internal_->append_null(ths->temp_str); | ||
525 | return ths->temp_str.data(); | ||
526 | \} | ||
527 | + cc extra => | ||
528 | + \#define aspell_string_enumeration_next_w(type, ths) \\ | ||
529 | + aspell_cast_(const type *, aspell_string_enumeration_next_wide(ths, sizeof(type))) | ||
530 | / | ||
531 | const string | ||
532 | |||
533 | + method: next wide | ||
534 | + c impl => | ||
535 | + const char * s = ths->next(); | ||
536 | + if (s == 0) { | ||
537 | + return s; | ||
538 | + } else if (ths->from_internal_ == 0) \{ | ||
539 | + assert(type_width == 1); | ||
540 | + return s; | ||
541 | + \} else \{ | ||
542 | + assert(type_width == ths->from_internal_->out_type_width()); | ||
543 | + ths->temp_str.clear(); | ||
544 | + ths->from_internal_->convert(s,-1,ths->temp_str); | ||
545 | + ths->from_internal_->append_null(ths->temp_str); | ||
546 | + return ths->temp_str.data(); | ||
547 | + \} | ||
548 | + / | ||
549 | + const void pointer | ||
550 | + int: type_width | ||
551 | } | ||
552 | group: info | ||
553 | { | ||
554 | diff --git a/common/convert.cpp b/common/convert.cpp | ||
555 | index 1add95a..7ae0317 100644 | ||
556 | --- a/common/convert.cpp | ||
557 | +++ b/common/convert.cpp | ||
558 | @@ -541,18 +541,25 @@ namespace acommon { | ||
559 | // Trivial Conversion | ||
560 | // | ||
561 | |||
562 | + const char * unsupported_null_term_wide_string_msg = | ||
563 | + "Null-terminated wide-character strings unsupported when used this way."; | ||
564 | + | ||
565 | template <typename Chr> | ||
566 | struct DecodeDirect : public Decode | ||
567 | { | ||
568 | + DecodeDirect() {type_width = sizeof(Chr);} | ||
569 | void decode(const char * in0, int size, FilterCharVector & out) const { | ||
570 | const Chr * in = reinterpret_cast<const Chr *>(in0); | ||
571 | - if (size == -1) { | ||
572 | + if (size == -sizeof(Chr)) { | ||
573 | for (;*in; ++in) | ||
574 | - out.append(*in); | ||
575 | + out.append(*in, sizeof(Chr)); | ||
576 | + } else if (size <= -1) { | ||
577 | + fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | ||
578 | + abort(); | ||
579 | } else { | ||
580 | - const Chr * stop = reinterpret_cast<const Chr *>(in0 +size); | ||
581 | + const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | ||
582 | for (;in != stop; ++in) | ||
583 | - out.append(*in); | ||
584 | + out.append(*in, sizeof(Chr)); | ||
585 | } | ||
586 | } | ||
587 | PosibErr<void> decode_ec(const char * in0, int size, | ||
588 | @@ -565,6 +572,7 @@ namespace acommon { | ||
589 | template <typename Chr> | ||
590 | struct EncodeDirect : public Encode | ||
591 | { | ||
592 | + EncodeDirect() {type_width = sizeof(Chr);} | ||
593 | void encode(const FilterChar * in, const FilterChar * stop, | ||
594 | CharVector & out) const { | ||
595 | for (; in != stop; ++in) { | ||
596 | @@ -594,11 +602,15 @@ namespace acommon { | ||
597 | template <typename Chr> | ||
598 | struct ConvDirect : public DirectConv | ||
599 | { | ||
600 | + ConvDirect() {type_width = sizeof(Chr);} | ||
601 | void convert(const char * in0, int size, CharVector & out) const { | ||
602 | - if (size == -1) { | ||
603 | + if (size == -sizeof(Chr)) { | ||
604 | const Chr * in = reinterpret_cast<const Chr *>(in0); | ||
605 | for (;*in != 0; ++in) | ||
606 | out.append(in, sizeof(Chr)); | ||
607 | + } else if (size <= -1) { | ||
608 | + fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | ||
609 | + abort(); | ||
610 | } else { | ||
611 | out.append(in0, size); | ||
612 | } | ||
613 | @@ -1121,5 +1133,20 @@ namespace acommon { | ||
614 | } | ||
615 | return 0; | ||
616 | } | ||
617 | - | ||
618 | + | ||
619 | + PosibErr<void> unsupported_null_term_wide_string_err_(const char * func) { | ||
620 | + static bool reported_to_stderr = false; | ||
621 | + PosibErr<void> err = make_err(other_error, unsupported_null_term_wide_string_msg); | ||
622 | + if (!reported_to_stderr) { | ||
623 | + CERR.printf("ERROR: %s: %s\n", func, unsupported_null_term_wide_string_msg); | ||
624 | + reported_to_stderr = true; | ||
625 | + } | ||
626 | + return err; | ||
627 | + } | ||
628 | + | ||
629 | + void unsupported_null_term_wide_string_abort_(const char * func) { | ||
630 | + CERR.printf("%s: %s\n", unsupported_null_term_wide_string_msg); | ||
631 | + abort(); | ||
632 | + } | ||
633 | + | ||
634 | } | ||
635 | diff --git a/common/convert.hpp b/common/convert.hpp | ||
636 | index 76332ee..c948973 100644 | ||
637 | --- a/common/convert.hpp | ||
638 | +++ b/common/convert.hpp | ||
639 | @@ -7,6 +7,8 @@ | ||
640 | #ifndef ASPELL_CONVERT__HPP | ||
641 | #define ASPELL_CONVERT__HPP | ||
642 | |||
643 | +#include "settings.h" | ||
644 | + | ||
645 | #include "string.hpp" | ||
646 | #include "posib_err.hpp" | ||
647 | #include "char_vector.hpp" | ||
648 | @@ -25,8 +27,9 @@ namespace acommon { | ||
649 | typedef const Config CacheConfig; | ||
650 | typedef const char * CacheKey; | ||
651 | String key; | ||
652 | + int type_width; // type width in bytes | ||
653 | bool cache_key_eq(const char * l) const {return key == l;} | ||
654 | - ConvBase() {} | ||
655 | + ConvBase() : type_width(1) {} | ||
656 | private: | ||
657 | ConvBase(const ConvBase &); | ||
658 | void operator=(const ConvBase &); | ||
659 | @@ -56,6 +59,8 @@ namespace acommon { | ||
660 | virtual ~Encode() {} | ||
661 | }; | ||
662 | struct DirectConv { // convert directly from in_code to out_code. | ||
663 | + int type_width; // type width in bytes | ||
664 | + DirectConv() : type_width(1) {} | ||
665 | // should not take ownership of decode and encode. | ||
666 | // decode and encode guaranteed to stick around for the life | ||
667 | // of the object. | ||
668 | @@ -126,6 +131,9 @@ namespace acommon { | ||
669 | const char * in_code() const {return decode_->key.c_str();} | ||
670 | const char * out_code() const {return encode_->key.c_str();} | ||
671 | |||
672 | + int in_type_width() const {return decode_->type_width;} | ||
673 | + int out_type_width() const {return encode_->type_width;} | ||
674 | + | ||
675 | void append_null(CharVector & out) const | ||
676 | { | ||
677 | const char nul[4] = {0,0,0,0}; // 4 should be enough | ||
678 | @@ -191,6 +199,10 @@ namespace acommon { | ||
679 | } | ||
680 | } | ||
681 | |||
682 | + void convert(const void * in, int size, CharVector & out) { | ||
683 | + convert(static_cast<const char *>(in), size, out); | ||
684 | + } | ||
685 | + | ||
686 | void generic_convert(const char * in, int size, CharVector & out); | ||
687 | |||
688 | }; | ||
689 | @@ -412,6 +424,30 @@ namespace acommon { | ||
690 | return operator()(str, str + byte_size);} | ||
691 | }; | ||
692 | |||
693 | +#ifdef SLOPPY_NULL_TERM_STRINGS | ||
694 | + static const bool sloppy_null_term_strings = true; | ||
695 | +#else | ||
696 | + static const bool sloppy_null_term_strings = false; | ||
697 | +#endif | ||
698 | + | ||
699 | + PosibErr<void> unsupported_null_term_wide_string_err_(const char * func); | ||
700 | + void unsupported_null_term_wide_string_abort_(const char * func); | ||
701 | + | ||
702 | + static inline PosibErr<int> get_correct_size(const char * func, int conv_type_width, int size) { | ||
703 | + if (sloppy_null_term_strings && size <= -1) | ||
704 | + return -conv_type_width; | ||
705 | + if (size <= -1 && -conv_type_width != size) | ||
706 | + return unsupported_null_term_wide_string_err_(func); | ||
707 | + return size; | ||
708 | + } | ||
709 | + static inline int get_correct_size(const char * func, int conv_type_width, int size, int type_width) { | ||
710 | + if ((sloppy_null_term_strings || type_width <= -1) && size <= -1) | ||
711 | + return -conv_type_width; | ||
712 | + if (size <= -1 && conv_type_width != type_width) | ||
713 | + unsupported_null_term_wide_string_abort_(func); | ||
714 | + return size; | ||
715 | + } | ||
716 | + | ||
717 | } | ||
718 | |||
719 | #endif | ||
720 | diff --git a/common/document_checker.cpp b/common/document_checker.cpp | ||
721 | index 5e510c4..0ccf1cd 100644 | ||
722 | --- a/common/document_checker.cpp | ||
723 | +++ b/common/document_checker.cpp | ||
724 | @@ -44,7 +44,9 @@ namespace acommon { | ||
725 | void DocumentChecker::process(const char * str, int size) | ||
726 | { | ||
727 | proc_str_.clear(); | ||
728 | - conv_->decode(str, size, proc_str_); | ||
729 | + PosibErr<int> fixed_size = get_correct_size("aspell_document_checker_process", conv_->in_type_width(), size); | ||
730 | + if (!fixed_size.has_err()) | ||
731 | + conv_->decode(str, fixed_size, proc_str_); | ||
732 | proc_str_.append(0); | ||
733 | FilterChar * begin = proc_str_.pbegin(); | ||
734 | FilterChar * end = proc_str_.pend() - 1; | ||
735 | @@ -53,6 +55,19 @@ namespace acommon { | ||
736 | tokenizer_->reset(begin, end); | ||
737 | } | ||
738 | |||
739 | + void DocumentChecker::process_wide(const void * str, int size, int type_width) | ||
740 | + { | ||
741 | + proc_str_.clear(); | ||
742 | + int fixed_size = get_correct_size("aspell_document_checker_process", conv_->in_type_width(), size, type_width); | ||
743 | + conv_->decode(static_cast<const char *>(str), fixed_size, proc_str_); | ||
744 | + proc_str_.append(0); | ||
745 | + FilterChar * begin = proc_str_.pbegin(); | ||
746 | + FilterChar * end = proc_str_.pend() - 1; | ||
747 | + if (filter_) | ||
748 | + filter_->process(begin, end); | ||
749 | + tokenizer_->reset(begin, end); | ||
750 | + } | ||
751 | + | ||
752 | Token DocumentChecker::next_misspelling() | ||
753 | { | ||
754 | bool correct; | ||
755 | diff --git a/common/document_checker.hpp b/common/document_checker.hpp | ||
756 | index d35bb88..11a3c73 100644 | ||
757 | --- a/common/document_checker.hpp | ||
758 | +++ b/common/document_checker.hpp | ||
759 | @@ -36,6 +36,7 @@ namespace acommon { | ||
760 | PosibErr<void> setup(Tokenizer *, Speller *, Filter *); | ||
761 | void reset(); | ||
762 | void process(const char * str, int size); | ||
763 | + void process_wide(const void * str, int size, int type_width); | ||
764 | Token next_misspelling(); | ||
765 | |||
766 | Filter * filter() {return filter_;} | ||
767 | diff --git a/common/version.cpp b/common/version.cpp | ||
768 | index 414d938..9e60b75 100644 | ||
769 | --- a/common/version.cpp | ||
770 | +++ b/common/version.cpp | ||
771 | @@ -1,8 +1,17 @@ | ||
772 | #include "settings.h" | ||
773 | |||
774 | -extern "C" const char * aspell_version_string() { | ||
775 | #ifdef NDEBUG | ||
776 | - return VERSION " NDEBUG"; | ||
777 | +# define NDEBUG_STR " NDEBUG" | ||
778 | +#else | ||
779 | +# define NDEBUG_STR | ||
780 | +#endif | ||
781 | + | ||
782 | +#ifdef SLOPPY_NULL_TERM_STRINGS | ||
783 | +# define SLOPPY_STR " SLOPPY" | ||
784 | +#else | ||
785 | +# define SLOPPY_STR | ||
786 | #endif | ||
787 | - return VERSION; | ||
788 | + | ||
789 | +extern "C" const char * aspell_version_string() { | ||
790 | + return VERSION NDEBUG_STR SLOPPY_STR; | ||
791 | } | ||
792 | diff --git a/configure.ac b/configure.ac | ||
793 | index 60e3b39..a5d51e3 100644 | ||
794 | --- a/configure.ac | ||
795 | +++ b/configure.ac | ||
796 | @@ -73,6 +73,9 @@ AC_ARG_ENABLE(filter-version-control, | ||
797 | AC_ARG_ENABLE(32-bit-hash-fun, | ||
798 | AS_HELP_STRING([--enable-32-bit-hash-fun],[use 32-bit hash function for compiled dictionaries])) | ||
799 | |||
800 | +AC_ARG_ENABLE(sloppy-null-term-strings, | ||
801 | + AS_HELP_STRING([--enable-sloppy-null-term-strings],[allows allow null terminated UCS-2 and UCS-4 strings])) | ||
802 | + | ||
803 | AC_ARG_ENABLE(pspell-compatibility, | ||
804 | AS_HELP_STRING([--disable-pspell-compatibility],[don't install pspell compatibility libraries])) | ||
805 | |||
806 | @@ -141,6 +144,11 @@ then | ||
807 | AC_DEFINE(USE_32_BIT_HASH_FUN, 1, [Defined if 32-bit hash function should be used for compiled dictionaries.]) | ||
808 | fi | ||
809 | |||
810 | +if test "$enable_sloppy_null_term_strings" = "yes" | ||
811 | +then | ||
812 | + AC_DEFINE(SLOPPY_NULL_TERM_STRINGS, 1, [Defined if null-terminated UCS-2 and UCS-4 strings should always be allowed.]) | ||
813 | +fi | ||
814 | + | ||
815 | AM_CONDITIONAL(PSPELL_COMPATIBILITY, | ||
816 | [test "$enable_pspell_compatibility" != "no"]) | ||
817 | AM_CONDITIONAL(INCREMENTED_SONAME, | ||
818 | diff --git a/manual/aspell.texi b/manual/aspell.texi | ||
819 | index 45fa091..f400e06 100644 | ||
820 | --- a/manual/aspell.texi | ||
821 | +++ b/manual/aspell.texi | ||
822 | @@ -158,7 +158,8 @@ Installing | ||
823 | |||
824 | * Generic Install Instructions:: | ||
825 | * HTML Manuals and "make clean":: | ||
826 | -* Curses Notes:: | ||
827 | +* Curses Notes:: | ||
828 | +* Upgrading from Aspell 0.60.7:: | ||
829 | * Loadable Filter Notes:: | ||
830 | * Upgrading from Aspell 0.50:: | ||
831 | * Upgrading from Aspell .33/Pspell .12:: | ||
832 | @@ -2206,18 +2207,26 @@ int correct = aspell_speller_check(spell_checker, @var{word}, @var{size}); | ||
833 | @end smallexample | ||
834 | |||
835 | @noindent | ||
836 | -@var{word} is expected to be a @code{const char *} character | ||
837 | -string. If the encoding is set to be @code{ucs-2} or | ||
838 | -@code{ucs-4} @var{word} is expected to be a cast | ||
839 | -from either @code{const u16int *} or @code{const u32int *} | ||
840 | -respectively. @code{u16int} and @code{u32int} are generally | ||
841 | -@code{unsigned short} and @code{unsigned int} respectively. | ||
842 | -@var{size} is the length of the string or @code{-1} if the string | ||
843 | -is null terminated. If the string is a cast from @code{const u16int | ||
844 | -*} or @code{const u32int *} then @code{@i{size}} is the amount of | ||
845 | -space in bytes the string takes up after being cast to @code{const | ||
846 | -char *} and not the true size of the string. @code{sspell_speller_check} | ||
847 | -will return @code{0} if it is not found and non-zero otherwise. | ||
848 | +@var{word} is expected to be a @code{const char *} character string. | ||
849 | +@var{size} is the length of the string or @code{-1} if the string is | ||
850 | +null terminated. @code{aspell_speller_check} will return @code{0} if it is not found | ||
851 | +and non-zero otherwise. | ||
852 | + | ||
853 | +If you are using the @code{ucs-2} or @code{ucs-4} encoding then the | ||
854 | +string is expected to be either a 2 or 4 byte wide integer | ||
855 | +(respectively) and the @code{_w} macro vesion should be used: | ||
856 | + | ||
857 | +@smallexample | ||
858 | +int correct = aspell_speller_check_w(spell_checker, @var{word}, @var{size}); | ||
859 | +@end smallexample | ||
860 | + | ||
861 | +The macro will cast the string to to the correct type and convert | ||
862 | +@var{size} into bytes for you and then a call the special wide version of the | ||
863 | +function that will make sure the encoding is correct for the type | ||
864 | +passed in. For compatibility with older versions of Aspell the normal | ||
865 | +non-wide functions can still be used provided that the size of the | ||
866 | +string, in bytes, is also passed in. Null terminated @code{ucs-2} or | ||
867 | +@code{ucs-4} are no longer supported when using the non-wide functions. | ||
868 | |||
869 | If the word is not correct, then the @code{suggest} method can be used | ||
870 | to come up with likely replacements. | ||
871 | @@ -2236,7 +2245,28 @@ delete_aspell_string_enumeration(elements); | ||
872 | |||
873 | Notice how @code{elements} is deleted but @code{suggestions} is not. | ||
874 | The value returned by @code{suggestions} is only valid to the next | ||
875 | -call to @code{suggest}. Once a replacement is made the | ||
876 | +call to @code{suggest}. | ||
877 | + | ||
878 | +If you are using the @code{ucs-2} or @code{ucs-4} encoding then, in | ||
879 | +addition to using the @code{_w} macro for the @code{suggest} method, you | ||
880 | +should also use the @code{_w} macro with the @code{next} method which | ||
881 | +will cast the string to the correct type for you. For example, if you | ||
882 | +are using the @code{ucs-2} encoding and the string is a @code{const | ||
883 | +uint16_t *} then you should use: | ||
884 | + | ||
885 | +@smallexample | ||
886 | +AspellWordList * suggestions = aspell_speller_suggest_w(spell_checker, | ||
887 | + @var{word}, @var{size}); | ||
888 | +AspellStringEnumeration * elements = aspell_word_list_elements(suggestions); | ||
889 | +const uint16_t * word; | ||
890 | +while ( (word = aspell_string_enumeration_next_w(uint16_t, aspell_elements)) != NULL ) | ||
891 | +@{ | ||
892 | + // add to suggestion list | ||
893 | +@} | ||
894 | +delete_aspell_string_enumeration(elements); | ||
895 | +@end smallexample | ||
896 | + | ||
897 | +Once a replacement is made the | ||
898 | @code{store_repl} method should be used to communicate the replacement | ||
899 | pair back to the spell checker (for the reason, @pxref{Notes on | ||
900 | Storing Replacement Pairs}). Its usage is as follows: | ||
901 | diff --git a/manual/readme.texi b/manual/readme.texi | ||
902 | index 669ab8e..531721f 100644 | ||
903 | --- a/manual/readme.texi | ||
904 | +++ b/manual/readme.texi | ||
905 | @@ -15,15 +15,16 @@ The latest version can always be found at GNU Aspell's home page at | ||
906 | @uref{http://aspell.net}. | ||
907 | |||
908 | @menu | ||
909 | -* Generic Install Instructions:: | ||
910 | -* HTML Manuals and "make clean":: | ||
911 | -* Curses Notes:: | ||
912 | -* Loadable Filter Notes:: | ||
913 | -* Using 32-Bit Dictionaries on a 64-Bit System:: | ||
914 | -* Upgrading from Aspell 0.50:: | ||
915 | -* Upgrading from Aspell .33/Pspell .12:: | ||
916 | -* Upgrading from a Pre-0.50 snapshot:: | ||
917 | -* WIN32 Notes:: | ||
918 | +* Generic Install Instructions:: | ||
919 | +* HTML Manuals and "make clean":: | ||
920 | +* Curses Notes:: | ||
921 | +* Upgrading from Aspell 0.60.7:: | ||
922 | +* Loadable Filter Notes:: | ||
923 | +* Using 32-Bit Dictionaries on a 64-Bit System:: | ||
924 | +* Upgrading from Aspell 0.50:: | ||
925 | +* Upgrading from Aspell .33/Pspell .12:: | ||
926 | +* Upgrading from a Pre-0.50 snapshot:: | ||
927 | +* WIN32 Notes:: | ||
928 | @end menu | ||
929 | |||
930 | @node Generic Install Instructions | ||
931 | @@ -121,17 +122,62 @@ In addition your system must also support the @code{mblen} function. | ||
932 | Although this function was defined in the ISO C89 standard (ANSI | ||
933 | X3.159-1989), not all systems have it. | ||
934 | |||
935 | +@node Upgrading from Aspell 0.60.7 | ||
936 | +@appendixsec Upgrading from Aspell 0.60.7 | ||
937 | + | ||
938 | +To prevent a potentially unbounded buffer over-read, Aspell no longer | ||
939 | +supports null-terminated UCS-2 and UCS-4 encoded strings with the | ||
940 | +original C API. Null-termianted 8-bit or UTF-8 encoded strings are | ||
941 | +still supported, as are UCS-2 and UCS-4 encoded strings when the | ||
942 | +length is passed in. | ||
943 | + | ||
944 | +As of Aspell 0.60.8 a function from the original API that expects an | ||
945 | +encoded string as a parameter will return meaningless results (or an | ||
946 | +error code) if string is null terminated and the encoding is set to | ||
947 | +@code{ucs-2} or @code{ucs-4}. In addition, a single: | ||
948 | +@example | ||
949 | +ERROR: aspell_speller_check: Null-terminated wide-character strings unsupported when used this way. | ||
950 | +@end example | ||
951 | +will be printed to standard error the first time one of those | ||
952 | +functions is called. | ||
953 | + | ||
954 | +Application that use null-terminated UCS-2/4 strings should either (1) | ||
955 | +use the interface intended for working with wide-characters | ||
956 | +(@xref{Through the C API}); or (2) define | ||
957 | +@code{ASPELL_ENCODE_SETTING_SECURE} before including @code{aspell.h}. | ||
958 | +In the latter case is is important that the application explicitly | ||
959 | +sets the encoding to a known value. Defining | ||
960 | +@code{ASPELL_ENCODE_SETTING_SECURE} and not setting the encoding | ||
961 | +explicitly or allowing user of the application to set the encoding | ||
962 | +could result in an unbounded buffer over-read. | ||
963 | + | ||
964 | +If it is necessary to preserve binary compatibility with older | ||
965 | +versions of Aspell, the easiest thing would be to determine the length | ||
966 | +of the UCS-2/4 string---in bytes---and pass that in. Due to an | ||
967 | +implemenation detail, existing API functions can be made to work with | ||
968 | +null-terminated UCS-2/4 strings safely by passing in either @code{-2} | ||
969 | +or @code{-4} (corresponding to the width of the character type) as the | ||
970 | +size. Doing so, however, will cause a buffer over-read for unpatched | ||
971 | +version of Aspell. To avoid this it will be necessary to parse the | ||
972 | +version string to determine the correct value to use. However, no | ||
973 | +official support will be provided for the latter method. | ||
974 | + | ||
975 | +If the application can not be recompiled, then Aspell can be configured | ||
976 | +to preserve the old behavior by passing | ||
977 | +@option{--enable-sloppy-null-term-strings} to @command{configure}. When Aspell | ||
978 | +is compiled this way the version string will include the string | ||
979 | +@samp{ SLOPPY}. | ||
980 | + | ||
981 | @node Loadable Filter Notes | ||
982 | @appendixsec Loadable Filter Notes | ||
983 | - | ||
984 | + | ||
985 | Support for being able to load additional filter modules at run-time | ||
986 | has only been verified to work on Linux platforms. If you get linker | ||
987 | errors when trying to use a filter, then it is likely that loadable | ||
988 | filter support is not working yet on your platform. Thus, in order to | ||
989 | get Aspell to work correctly you will need to avoid compiling the | ||
990 | filters as individual modules by using the | ||
991 | -@option{--enable-compile-in-filters} when configuring Aspell with | ||
992 | -@command{./configure}. | ||
993 | +@option{--enable-compile-in-filters} @command{configure} option. | ||
994 | |||
995 | @node Using 32-Bit Dictionaries on a 64-Bit System | ||
996 | @appendixsec Using 32-Bit Dictionaries on a 64-Bit System | ||
997 | -- | ||
998 | 2.17.1 | ||
999 | |||
diff --git a/meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch new file mode 100644 index 0000000000..9569ddeebe --- /dev/null +++ b/meta/recipes-support/aspell/aspell/CVE-2019-20433-0002.patch | |||
@@ -0,0 +1,68 @@ | |||
1 | From cefd447e5528b08bb0cd6656bc52b4255692cefc Mon Sep 17 00:00:00 2001 | ||
2 | From: Kevin Atkinson <kevina@gnu.org> | ||
3 | Date: Sat, 17 Aug 2019 20:25:21 -0400 | ||
4 | Subject: [PATCH 2/2] Increment library version to reflect API changes. | ||
5 | |||
6 | CVE: CVE-2019-20433 | ||
7 | Upstream-Status: Backport [https://github.com/GNUAspell/aspell/commit/cefd447e5528b08bb0cd6656bc52b4255692cefc] | ||
8 | |||
9 | Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com> | ||
10 | --- | ||
11 | Makefile.am | 31 +++++++++++++++++-------------- | ||
12 | 1 file changed, 17 insertions(+), 14 deletions(-) | ||
13 | |||
14 | diff --git a/Makefile.am b/Makefile.am | ||
15 | index 7e15851..19dc044 100644 | ||
16 | --- a/Makefile.am | ||
17 | +++ b/Makefile.am | ||
18 | @@ -94,18 +94,25 @@ libaspell_la_SOURCES =\ | ||
19 | |||
20 | libaspell_la_LIBADD = $(LTLIBINTL) $(PTHREAD_LIB) | ||
21 | |||
22 | -## Libtool to so name | ||
23 | -## C:R:A => (C-A).(A).(R) | ||
24 | -## 16:5:0 => 16.0.5 | ||
25 | -## 16:5:1 => 15.1.5 | ||
26 | -## 18:0:2 => 16.2.0 | ||
27 | -## 17:0:2 => 15.2.0 | ||
28 | - | ||
29 | +## The version string is current[:revision[:age]] | ||
30 | +## | ||
31 | +## Before a release that has changed the source code at all | ||
32 | +## increment revision. | ||
33 | +## | ||
34 | +## After merging changes that have changed the API in a backwards | ||
35 | +## comptable way set revision to 0 and bump both current and age. | ||
36 | +## | ||
37 | +## Do not change the API in a backwards incompatible way. | ||
38 | +## | ||
39 | +## See "Libtool: Updating version info" | ||
40 | +## (https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html) | ||
41 | +## for more into | ||
42 | +## | ||
43 | if INCREMENTED_SONAME | ||
44 | -libaspell_la_LDFLAGS = -version-info 18:0:2 -no-undefined | ||
45 | +libaspell_la_LDFLAGS = -version-info 19:0:3 -no-undefined | ||
46 | else | ||
47 | ## Use C-1:R:A | ||
48 | -libaspell_la_LDFLAGS = -version-info 17:0:2 -no-undefined | ||
49 | +libaspell_la_LDFLAGS = -version-info 18:0:3 -no-undefined | ||
50 | endif | ||
51 | |||
52 | if PSPELL_COMPATIBILITY | ||
53 | @@ -113,11 +120,7 @@ libpspell_la_SOURCES = lib/dummy.cpp | ||
54 | |||
55 | libpspell_la_LIBADD = libaspell.la | ||
56 | |||
57 | -if INCREMENTED_SONAME | ||
58 | -libpspell_la_LDFLAGS = -version-info 18:0:2 -no-undefined | ||
59 | -else | ||
60 | -libpspell_la_LDFLAGS = -version-info 17:0:2 -no-undefined | ||
61 | -endif | ||
62 | +libpspell_la_LDFLAGS = $(libaspell_la_LDFLAGS) | ||
63 | |||
64 | endif | ||
65 | |||
66 | -- | ||
67 | 2.17.1 | ||
68 | |||
diff --git a/meta/recipes-support/aspell/aspell_0.60.7.bb b/meta/recipes-support/aspell/aspell_0.60.7.bb index b565cb3c6e..1e104c263c 100644 --- a/meta/recipes-support/aspell/aspell_0.60.7.bb +++ b/meta/recipes-support/aspell/aspell_0.60.7.bb | |||
@@ -8,6 +8,8 @@ PR = "r1" | |||
8 | 8 | ||
9 | SRC_URI = "${GNU_MIRROR}/aspell/aspell-${PV}.tar.gz \ | 9 | SRC_URI = "${GNU_MIRROR}/aspell/aspell-${PV}.tar.gz \ |
10 | file://0001-Fix-various-bugs-found-by-OSS-Fuze.patch \ | 10 | file://0001-Fix-various-bugs-found-by-OSS-Fuze.patch \ |
11 | file://CVE-2019-20433-0001.patch \ | ||
12 | file://CVE-2019-20433-0002.patch \ | ||
11 | " | 13 | " |
12 | SRC_URI[md5sum] = "8ef2252609c511cd2bb26f3a3932ef28" | 14 | SRC_URI[md5sum] = "8ef2252609c511cd2bb26f3a3932ef28" |
13 | SRC_URI[sha256sum] = "5ca8fc8cb0370cc6c9eb5b64c6d1bc5d57b3750dbf17887726c3407d833b70e4" | 15 | SRC_URI[sha256sum] = "5ca8fc8cb0370cc6c9eb5b64c6d1bc5d57b3750dbf17887726c3407d833b70e4" |