Fix overflow in nss files parser
[glibc.git] / libio / strops.c
blob05270ce4073e46870a41cac64797f56bc22bb32d
1 /* Copyright (C) 1993, 1997-2003, 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 <stdio_ext.h>
34 void
35 _IO_str_init_static_internal (sf, ptr, size, pstart)
36 _IO_strfile *sf;
37 char *ptr;
38 _IO_size_t size;
39 char *pstart;
41 _IO_FILE *fp = &sf->_sbf._f;
42 char *end;
44 if (size == 0)
45 end = __rawmemchr (ptr, '\0');
46 else if ((_IO_size_t) ptr + size > (_IO_size_t) ptr)
47 end = ptr + size;
48 else
49 end = (char *) -1;
50 INTUSE(_IO_setb) (fp, ptr, end, 0);
52 fp->_IO_write_base = ptr;
53 fp->_IO_read_base = ptr;
54 fp->_IO_read_ptr = ptr;
55 if (pstart)
57 fp->_IO_write_ptr = pstart;
58 fp->_IO_write_end = end;
59 fp->_IO_read_end = pstart;
61 else
63 fp->_IO_write_ptr = ptr;
64 fp->_IO_write_end = ptr;
65 fp->_IO_read_end = end;
67 /* A null _allocate_buffer function flags the strfile as being static. */
68 sf->_s._allocate_buffer = (_IO_alloc_type) 0;
71 void
72 _IO_str_init_static (sf, ptr, size, pstart)
73 _IO_strfile *sf;
74 char *ptr;
75 int size;
76 char *pstart;
78 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
81 void
82 _IO_str_init_readonly (sf, ptr, size)
83 _IO_strfile *sf;
84 const char *ptr;
85 int size;
87 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
88 sf->_sbf._f._IO_file_flags |= _IO_NO_WRITES;
91 int
92 _IO_str_overflow (fp, c)
93 _IO_FILE *fp;
94 int c;
96 int flush_only = c == EOF;
97 _IO_size_t pos;
98 if (fp->_flags & _IO_NO_WRITES)
99 return flush_only ? 0 : EOF;
100 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
102 fp->_flags |= _IO_CURRENTLY_PUTTING;
103 fp->_IO_write_ptr = fp->_IO_read_ptr;
104 fp->_IO_read_ptr = fp->_IO_read_end;
106 pos = fp->_IO_write_ptr - fp->_IO_write_base;
107 if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))
109 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
110 return EOF;
111 else
113 char *new_buf;
114 char *old_buf = fp->_IO_buf_base;
115 size_t old_blen = _IO_blen (fp);
116 _IO_size_t new_size = 2 * old_blen + 100;
117 if (new_size < old_blen)
118 return EOF;
119 new_buf
120 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
121 if (new_buf == NULL)
123 /* __ferror(fp) = 1; */
124 return EOF;
126 if (old_buf)
128 memcpy (new_buf, old_buf, old_blen);
129 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
130 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
131 fp->_IO_buf_base = NULL;
133 memset (new_buf + old_blen, '\0', new_size - old_blen);
135 INTUSE(_IO_setb) (fp, new_buf, new_buf + new_size, 1);
136 fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
137 fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
138 fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
139 fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
141 fp->_IO_write_base = new_buf;
142 fp->_IO_write_end = fp->_IO_buf_end;
146 if (!flush_only)
147 *fp->_IO_write_ptr++ = (unsigned char) c;
148 if (fp->_IO_write_ptr > fp->_IO_read_end)
149 fp->_IO_read_end = fp->_IO_write_ptr;
150 return c;
152 INTDEF(_IO_str_overflow)
155 _IO_str_underflow (fp)
156 _IO_FILE *fp;
158 if (fp->_IO_write_ptr > fp->_IO_read_end)
159 fp->_IO_read_end = fp->_IO_write_ptr;
160 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
162 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
163 fp->_IO_read_ptr = fp->_IO_write_ptr;
164 fp->_IO_write_ptr = fp->_IO_write_end;
166 if (fp->_IO_read_ptr < fp->_IO_read_end)
167 return *((unsigned char *) fp->_IO_read_ptr);
168 else
169 return EOF;
171 INTDEF(_IO_str_underflow)
173 /* The size of the valid part of the buffer. */
175 _IO_ssize_t
176 _IO_str_count (fp)
177 _IO_FILE *fp;
179 return ((fp->_IO_write_ptr > fp->_IO_read_end
180 ? fp->_IO_write_ptr : fp->_IO_read_end)
181 - fp->_IO_read_base);
185 static int
186 enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
188 if ((_IO_ssize_t) offset <= _IO_blen (fp))
189 return 0;
191 _IO_ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
193 /* Try to enlarge the buffer. */
194 if (fp->_flags & _IO_USER_BUF)
195 /* User-provided buffer. */
196 return 1;
198 _IO_size_t newsize = offset + 100;
199 char *oldbuf = fp->_IO_buf_base;
200 char *newbuf
201 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize);
202 if (newbuf == NULL)
203 return 1;
205 if (oldbuf != NULL)
207 memcpy (newbuf, oldbuf, _IO_blen (fp));
208 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
209 /* Make sure _IO_setb won't try to delete
210 _IO_buf_base. */
211 fp->_IO_buf_base = NULL;
214 INTUSE(_IO_setb) (fp, newbuf, newbuf + newsize, 1);
216 if (reading)
218 fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
219 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
220 fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
221 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
223 fp->_IO_read_base = newbuf;
224 fp->_IO_read_end = fp->_IO_buf_end;
226 else
228 fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
229 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
230 fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
231 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
233 fp->_IO_write_base = newbuf;
234 fp->_IO_write_end = fp->_IO_buf_end;
237 /* Clear the area between the last write position and th
238 new position. */
239 assert (offset >= oldend);
240 if (reading)
241 memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
242 else
243 memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
245 return 0;
249 _IO_off64_t
250 _IO_str_seekoff (fp, offset, dir, mode)
251 _IO_FILE *fp;
252 _IO_off64_t offset;
253 int dir;
254 int mode;
256 _IO_off64_t new_pos;
258 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
259 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
261 if (mode == 0)
263 /* Don't move any pointers. But there is no clear indication what
264 mode FP is in. Let's guess. */
265 if (fp->_IO_file_flags & _IO_NO_WRITES)
266 new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
267 else
268 new_pos = fp->_IO_write_ptr - fp->_IO_write_base;
270 else
272 _IO_ssize_t cur_size = _IO_str_count(fp);
273 new_pos = EOF;
275 /* Move the get pointer, if requested. */
276 if (mode & _IOS_INPUT)
278 switch (dir)
280 case _IO_seek_end:
281 offset += cur_size;
282 break;
283 case _IO_seek_cur:
284 offset += fp->_IO_read_ptr - fp->_IO_read_base;
285 break;
286 default: /* case _IO_seek_set: */
287 break;
289 if (offset < 0)
290 return EOF;
291 if ((_IO_ssize_t) offset > cur_size
292 && enlarge_userbuf (fp, offset, 1) != 0)
293 return EOF;
294 fp->_IO_read_ptr = fp->_IO_read_base + offset;
295 fp->_IO_read_end = fp->_IO_read_base + cur_size;
296 new_pos = offset;
299 /* Move the put pointer, if requested. */
300 if (mode & _IOS_OUTPUT)
302 switch (dir)
304 case _IO_seek_end:
305 offset += cur_size;
306 break;
307 case _IO_seek_cur:
308 offset += fp->_IO_write_ptr - fp->_IO_write_base;
309 break;
310 default: /* case _IO_seek_set: */
311 break;
313 if (offset < 0)
314 return EOF;
315 if ((_IO_ssize_t) offset > cur_size
316 && enlarge_userbuf (fp, offset, 0) != 0)
317 return EOF;
318 fp->_IO_write_ptr = fp->_IO_write_base + offset;
319 new_pos = offset;
322 return new_pos;
324 INTDEF(_IO_str_seekoff)
327 _IO_str_pbackfail (fp, c)
328 _IO_FILE *fp;
329 int c;
331 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
332 return EOF;
333 return INTUSE(_IO_default_pbackfail) (fp, c);
335 INTDEF(_IO_str_pbackfail)
337 void
338 _IO_str_finish (fp, dummy)
339 _IO_FILE *fp;
340 int dummy;
342 if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
343 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
344 fp->_IO_buf_base = NULL;
346 INTUSE(_IO_default_finish) (fp, 0);
349 const struct _IO_jump_t _IO_str_jumps =
351 JUMP_INIT_DUMMY,
352 JUMP_INIT(finish, _IO_str_finish),
353 JUMP_INIT(overflow, INTUSE(_IO_str_overflow)),
354 JUMP_INIT(underflow, INTUSE(_IO_str_underflow)),
355 JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
356 JUMP_INIT(pbackfail, INTUSE(_IO_str_pbackfail)),
357 JUMP_INIT(xsputn, INTUSE(_IO_default_xsputn)),
358 JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)),
359 JUMP_INIT(seekoff, INTUSE(_IO_str_seekoff)),
360 JUMP_INIT(seekpos, _IO_default_seekpos),
361 JUMP_INIT(setbuf, _IO_default_setbuf),
362 JUMP_INIT(sync, _IO_default_sync),
363 JUMP_INIT(doallocate, INTUSE(_IO_default_doallocate)),
364 JUMP_INIT(read, _IO_default_read),
365 JUMP_INIT(write, _IO_default_write),
366 JUMP_INIT(seek, _IO_default_seek),
367 JUMP_INIT(close, _IO_default_close),
368 JUMP_INIT(stat, _IO_default_stat),
369 JUMP_INIT(showmanyc, _IO_default_showmanyc),
370 JUMP_INIT(imbue, _IO_default_imbue)