re_search_internal: Avoid overflow in computing re_malloc buffer size
[glibc.git] / libio / wstrops.c
blobc5aae7bc6a63587aa33e7bdd2d1f749e598644b6
1 /* Copyright (C) 1993,1997-1999,2001-2004, 2006 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA.
19 As a special exception, if you link the code in this file with
20 files compiled with a GNU compiler to produce an executable,
21 that does not cause the resulting executable to be covered by
22 the GNU Lesser General Public License. This exception does not
23 however invalidate any other reasons why the executable file
24 might be covered by the GNU Lesser General Public License.
25 This exception applies to code released by its copyright holders
26 in files containing the exception. */
28 #include <assert.h>
29 #include "strfile.h"
30 #include "libioP.h"
31 #include <string.h>
32 #include <wchar.h>
33 #include <stdio_ext.h>
35 void
36 _IO_wstr_init_static (fp, ptr, size, pstart)
37 _IO_FILE *fp;
38 wchar_t *ptr;
39 _IO_size_t size;
40 wchar_t *pstart;
42 wchar_t *end;
44 if (size == 0)
45 end = ptr + __wcslen (ptr);
46 else if ((_IO_size_t) ptr + size * sizeof (wchar_t) > (_IO_size_t) ptr)
47 end = ptr + size;
48 else
49 /* Even for misaligned ptr make sure there is integral number of wide
50 characters. */
51 end = ptr + (-1 - (_IO_size_t) ptr) / sizeof (wchar_t);
52 INTUSE(_IO_wsetb) (fp, ptr, end, 0);
54 fp->_wide_data->_IO_write_base = ptr;
55 fp->_wide_data->_IO_read_base = ptr;
56 fp->_wide_data->_IO_read_ptr = ptr;
57 if (pstart)
59 fp->_wide_data->_IO_write_ptr = pstart;
60 fp->_wide_data->_IO_write_end = end;
61 fp->_wide_data->_IO_read_end = pstart;
63 else
65 fp->_wide_data->_IO_write_ptr = ptr;
66 fp->_wide_data->_IO_write_end = ptr;
67 fp->_wide_data->_IO_read_end = end;
69 /* A null _allocate_buffer function flags the strfile as being static. */
70 (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0;
73 _IO_wint_t
74 _IO_wstr_overflow (fp, c)
75 _IO_FILE *fp;
76 _IO_wint_t c;
78 int flush_only = c == WEOF;
79 _IO_size_t pos;
80 if (fp->_flags & _IO_NO_WRITES)
81 return flush_only ? 0 : WEOF;
82 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
84 fp->_flags |= _IO_CURRENTLY_PUTTING;
85 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
86 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
88 pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
89 if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only))
91 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
92 return WEOF;
93 else
95 wchar_t *new_buf;
96 wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
97 size_t old_wblen = _IO_wblen (fp);
98 _IO_size_t new_size = 2 * old_wblen + 100;
99 if (new_size < old_wblen)
100 return EOF;
101 new_buf
102 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
103 * sizeof (wchar_t));
104 if (new_buf == NULL)
106 /* __ferror(fp) = 1; */
107 return WEOF;
109 if (old_buf)
111 __wmemcpy (new_buf, old_buf, old_wblen);
112 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
113 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
114 fp->_wide_data->_IO_buf_base = NULL;
117 wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
119 INTUSE(_IO_wsetb) (fp, new_buf, new_buf + new_size, 1);
120 fp->_wide_data->_IO_read_base =
121 new_buf + (fp->_wide_data->_IO_read_base - old_buf);
122 fp->_wide_data->_IO_read_ptr =
123 new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
124 fp->_wide_data->_IO_read_end =
125 new_buf + (fp->_wide_data->_IO_read_end - old_buf);
126 fp->_wide_data->_IO_write_ptr =
127 new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
129 fp->_wide_data->_IO_write_base = new_buf;
130 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
134 if (!flush_only)
135 *fp->_wide_data->_IO_write_ptr++ = c;
136 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
137 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
138 return c;
142 _IO_wint_t
143 _IO_wstr_underflow (fp)
144 _IO_FILE *fp;
146 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
147 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
148 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
150 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
151 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
152 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
154 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
155 return *fp->_wide_data->_IO_read_ptr;
156 else
157 return WEOF;
161 /* The size of the valid part of the buffer. */
162 _IO_ssize_t
163 _IO_wstr_count (fp)
164 _IO_FILE *fp;
166 struct _IO_wide_data *wd = fp->_wide_data;
168 return ((wd->_IO_write_ptr > wd->_IO_read_end
169 ? wd->_IO_write_ptr : wd->_IO_read_end)
170 - wd->_IO_read_base);
174 static int
175 enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
177 if ((_IO_ssize_t) offset <= _IO_blen (fp))
178 return 0;
180 struct _IO_wide_data *wd = fp->_wide_data;
182 _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
184 /* Try to enlarge the buffer. */
185 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
186 /* User-provided buffer. */
187 return 1;
189 _IO_size_t newsize = offset + 100;
190 wchar_t *oldbuf = wd->_IO_buf_base;
191 wchar_t *newbuf
192 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
193 * sizeof (wchar_t));
194 if (newbuf == NULL)
195 return 1;
197 if (oldbuf != NULL)
199 __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
200 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
201 /* Make sure _IO_setb won't try to delete
202 _IO_buf_base. */
203 wd->_IO_buf_base = NULL;
206 INTUSE(_IO_wsetb) (fp, newbuf, newbuf + newsize, 1);
208 if (reading)
210 wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
211 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
212 wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
213 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
215 wd->_IO_read_base = newbuf;
216 wd->_IO_read_end = wd->_IO_buf_end;
218 else
220 wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
221 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
222 wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
223 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
225 wd->_IO_write_base = newbuf;
226 wd->_IO_write_end = wd->_IO_buf_end;
229 /* Clear the area between the last write position and th
230 new position. */
231 assert (offset >= oldend);
232 if (reading)
233 wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
234 else
235 wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
237 return 0;
241 _IO_off64_t
242 _IO_wstr_seekoff (fp, offset, dir, mode)
243 _IO_FILE *fp;
244 _IO_off64_t offset;
245 int dir;
246 int mode;
248 _IO_off64_t new_pos;
250 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
251 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
253 if (mode == 0)
255 /* Don't move any pointers. But there is no clear indication what
256 mode FP is in. Let's guess. */
257 if (fp->_IO_file_flags & _IO_NO_WRITES)
258 new_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
259 else
260 new_pos = (fp->_wide_data->_IO_write_ptr
261 - fp->_wide_data->_IO_write_base);
263 else
265 _IO_ssize_t cur_size = _IO_wstr_count (fp);
266 new_pos = EOF;
268 /* Move the get pointer, if requested. */
269 if (mode & _IOS_INPUT)
271 switch (dir)
273 case _IO_seek_end:
274 offset += cur_size;
275 break;
276 case _IO_seek_cur:
277 offset += (fp->_wide_data->_IO_read_ptr
278 - fp->_wide_data->_IO_read_base);
279 break;
280 default: /* case _IO_seek_set: */
281 break;
283 if (offset < 0)
284 return EOF;
285 if ((_IO_ssize_t) offset > cur_size
286 && enlarge_userbuf (fp, offset, 1) != 0)
287 return EOF;
288 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
289 + offset);
290 fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
291 + cur_size);
292 new_pos = offset;
295 /* Move the put pointer, if requested. */
296 if (mode & _IOS_OUTPUT)
298 switch (dir)
300 case _IO_seek_end:
301 offset += cur_size;
302 break;
303 case _IO_seek_cur:
304 offset += (fp->_wide_data->_IO_write_ptr
305 - fp->_wide_data->_IO_write_base);
306 break;
307 default: /* case _IO_seek_set: */
308 break;
310 if (offset < 0)
311 return EOF;
312 if ((_IO_ssize_t) offset > cur_size
313 && enlarge_userbuf (fp, offset, 0) != 0)
314 return EOF;
315 fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
316 + offset);
317 new_pos = offset;
320 return new_pos;
323 _IO_wint_t
324 _IO_wstr_pbackfail (fp, c)
325 _IO_FILE *fp;
326 _IO_wint_t c;
328 if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
329 return WEOF;
330 return INTUSE(_IO_wdefault_pbackfail) (fp, c);
333 void
334 _IO_wstr_finish (fp, dummy)
335 _IO_FILE *fp;
336 int dummy;
338 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
339 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
340 fp->_wide_data->_IO_buf_base = NULL;
342 INTUSE(_IO_wdefault_finish) (fp, 0);
345 const struct _IO_jump_t _IO_wstr_jumps =
347 JUMP_INIT_DUMMY,
348 JUMP_INIT(finish, _IO_wstr_finish),
349 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
350 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
351 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
352 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
353 JUMP_INIT(xsputn, INTUSE(_IO_wdefault_xsputn)),
354 JUMP_INIT(xsgetn, INTUSE(_IO_wdefault_xsgetn)),
355 JUMP_INIT(seekoff, _IO_wstr_seekoff),
356 JUMP_INIT(seekpos, _IO_default_seekpos),
357 JUMP_INIT(setbuf, _IO_default_setbuf),
358 JUMP_INIT(sync, _IO_default_sync),
359 JUMP_INIT(doallocate, INTUSE(_IO_wdefault_doallocate)),
360 JUMP_INIT(read, _IO_default_read),
361 JUMP_INIT(write, _IO_default_write),
362 JUMP_INIT(seek, _IO_default_seek),
363 JUMP_INIT(close, _IO_default_close),
364 JUMP_INIT(stat, _IO_default_stat),
365 JUMP_INIT(showmanyc, _IO_default_showmanyc),
366 JUMP_INIT(imbue, _IO_default_imbue)