]> git.ipfire.org Git - thirdparty/glibc.git/blame - libio/strops.c
libio: Implement vtable verification [BZ #20191]
[thirdparty/glibc.git] / libio / strops.c
CommitLineData
f7a9f785 1/* Copyright (C) 1993-2016 Free Software Foundation, Inc.
41bdb6e2 2 This file is part of the GNU C Library.
96aa2d94 3
41bdb6e2
AJ
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.
96aa2d94 8
41bdb6e2
AJ
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
40a55d20 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2
AJ
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>.
41bdb6e2
AJ
17
18 As a special exception, if you link the code in this file with
19 files compiled with a GNU compiler to produce an executable,
20 that does not cause the resulting executable to be covered by
21 the GNU Lesser General Public License. This exception does not
22 however invalidate any other reasons why the executable file
23 might be covered by the GNU Lesser General Public License.
24 This exception applies to code released by its copyright holders
25 in files containing the exception. */
96aa2d94 26
107b8a92 27#include <assert.h>
96aa2d94
RM
28#include "strfile.h"
29#include "libioP.h"
30#include <string.h>
0d875352 31#include <stdio_ext.h>
96aa2d94 32
96aa2d94 33void
9dd346ff
JM
34_IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size,
35 char *pstart)
96aa2d94 36{
2ca8b1ee 37 _IO_FILE *fp = &sf->_sbf._f;
40a54e4d 38 char *end;
2ca8b1ee 39
96aa2d94 40 if (size == 0)
40a54e4d
UD
41 end = __rawmemchr (ptr, '\0');
42 else if ((_IO_size_t) ptr + size > (_IO_size_t) ptr)
43 end = ptr + size;
44 else
45 end = (char *) -1;
d18ea0c5 46 _IO_setb (fp, ptr, end, 0);
96aa2d94
RM
47
48 fp->_IO_write_base = ptr;
49 fp->_IO_read_base = ptr;
50 fp->_IO_read_ptr = ptr;
51 if (pstart)
52 {
53 fp->_IO_write_ptr = pstart;
40a54e4d 54 fp->_IO_write_end = end;
96aa2d94
RM
55 fp->_IO_read_end = pstart;
56 }
57 else
58 {
59 fp->_IO_write_ptr = ptr;
60 fp->_IO_write_end = ptr;
40a54e4d 61 fp->_IO_read_end = end;
96aa2d94 62 }
96aa2d94 63 /* A null _allocate_buffer function flags the strfile as being static. */
2ca8b1ee 64 sf->_s._allocate_buffer = (_IO_alloc_type) 0;
96aa2d94 65}
40a54e4d
UD
66
67void
9dd346ff 68_IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
40a54e4d
UD
69{
70 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
71}
96aa2d94
RM
72
73void
9dd346ff 74_IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
96aa2d94 75{
40a54e4d 76 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
2ca8b1ee 77 sf->_sbf._f._IO_file_flags |= _IO_NO_WRITES;
96aa2d94
RM
78}
79
80int
9dd346ff 81_IO_str_overflow (_IO_FILE *fp, int c)
96aa2d94
RM
82{
83 int flush_only = c == EOF;
8a523922 84 _IO_size_t pos;
96aa2d94
RM
85 if (fp->_flags & _IO_NO_WRITES)
86 return flush_only ? 0 : EOF;
96aa2d94
RM
87 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
88 {
96aa2d94 89 fp->_flags |= _IO_CURRENTLY_PUTTING;
8a523922
UD
90 fp->_IO_write_ptr = fp->_IO_read_ptr;
91 fp->_IO_read_ptr = fp->_IO_read_end;
96aa2d94 92 }
107b8a92 93 pos = fp->_IO_write_ptr - fp->_IO_write_base;
40a55d20 94 if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))
96aa2d94
RM
95 {
96 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
8a523922 97 return EOF;
96aa2d94
RM
98 else
99 {
100 char *new_buf;
8a523922 101 char *old_buf = fp->_IO_buf_base;
107b8a92
UD
102 size_t old_blen = _IO_blen (fp);
103 _IO_size_t new_size = 2 * old_blen + 100;
104 if (new_size < old_blen)
105 return EOF;
96aa2d94 106 new_buf
40a55d20 107 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
96aa2d94
RM
108 if (new_buf == NULL)
109 {
110 /* __ferror(fp) = 1; */
111 return EOF;
112 }
d64b6ad0 113 if (old_buf)
96aa2d94 114 {
107b8a92 115 memcpy (new_buf, old_buf, old_blen);
d64b6ad0 116 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
96aa2d94
RM
117 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
118 fp->_IO_buf_base = NULL;
119 }
107b8a92
UD
120 memset (new_buf + old_blen, '\0', new_size - old_blen);
121
d18ea0c5 122 _IO_setb (fp, new_buf, new_buf + new_size, 1);
8a523922
UD
123 fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
124 fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
125 fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
126 fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
127
96aa2d94 128 fp->_IO_write_base = new_buf;
f21acc89 129 fp->_IO_write_end = fp->_IO_buf_end;
96aa2d94 130 }
96aa2d94
RM
131 }
132
96aa2d94
RM
133 if (!flush_only)
134 *fp->_IO_write_ptr++ = (unsigned char) c;
8a523922
UD
135 if (fp->_IO_write_ptr > fp->_IO_read_end)
136 fp->_IO_read_end = fp->_IO_write_ptr;
96aa2d94
RM
137 return c;
138}
d18ea0c5 139libc_hidden_def (_IO_str_overflow)
96aa2d94
RM
140
141int
9dd346ff 142_IO_str_underflow (_IO_FILE *fp)
96aa2d94 143{
8a523922
UD
144 if (fp->_IO_write_ptr > fp->_IO_read_end)
145 fp->_IO_read_end = fp->_IO_write_ptr;
96aa2d94
RM
146 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
147 {
148 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
8a523922 149 fp->_IO_read_ptr = fp->_IO_write_ptr;
96aa2d94
RM
150 fp->_IO_write_ptr = fp->_IO_write_end;
151 }
96aa2d94 152 if (fp->_IO_read_ptr < fp->_IO_read_end)
195d0dd4 153 return *((unsigned char *) fp->_IO_read_ptr);
96aa2d94 154 else
0923a2c8 155 return EOF;
96aa2d94 156}
d18ea0c5 157libc_hidden_def (_IO_str_underflow)
96aa2d94 158
8a523922
UD
159/* The size of the valid part of the buffer. */
160
96aa2d94 161_IO_ssize_t
9dd346ff 162_IO_str_count (_IO_FILE *fp)
96aa2d94 163{
2604afb1
UD
164 return ((fp->_IO_write_ptr > fp->_IO_read_end
165 ? fp->_IO_write_ptr : fp->_IO_read_end)
40a55d20 166 - fp->_IO_read_base);
a68b0d31 167}
96aa2d94 168
107b8a92
UD
169
170static int
171enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
172{
173 if ((_IO_ssize_t) offset <= _IO_blen (fp))
174 return 0;
175
176 _IO_ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
177
178 /* Try to enlarge the buffer. */
179 if (fp->_flags & _IO_USER_BUF)
180 /* User-provided buffer. */
181 return 1;
182
183 _IO_size_t newsize = offset + 100;
184 char *oldbuf = fp->_IO_buf_base;
185 char *newbuf
186 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize);
187 if (newbuf == NULL)
188 return 1;
189
190 if (oldbuf != NULL)
191 {
192 memcpy (newbuf, oldbuf, _IO_blen (fp));
193 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
194 /* Make sure _IO_setb won't try to delete
195 _IO_buf_base. */
196 fp->_IO_buf_base = NULL;
197 }
198
d18ea0c5 199 _IO_setb (fp, newbuf, newbuf + newsize, 1);
107b8a92
UD
200
201 if (reading)
202 {
203 fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
204 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
205 fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
206 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
207
208 fp->_IO_read_base = newbuf;
209 fp->_IO_read_end = fp->_IO_buf_end;
210 }
211 else
212 {
213 fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
214 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
215 fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
216 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
217
218 fp->_IO_write_base = newbuf;
219 fp->_IO_write_end = fp->_IO_buf_end;
220 }
221
222 /* Clear the area between the last write position and th
223 new position. */
224 assert (offset >= oldend);
225 if (reading)
226 memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
227 else
228 memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
229
230 return 0;
231}
232
233
d64b6ad0 234_IO_off64_t
9dd346ff 235_IO_str_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
96aa2d94 236{
d64b6ad0 237 _IO_off64_t new_pos;
96aa2d94 238
dd7d45e8
UD
239 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
240 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
241
2eb45444 242 if (mode == 0)
96aa2d94 243 {
2eb45444
UD
244 /* Don't move any pointers. But there is no clear indication what
245 mode FP is in. Let's guess. */
246 if (fp->_IO_file_flags & _IO_NO_WRITES)
247 new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
248 else
249 new_pos = fp->_IO_write_ptr - fp->_IO_write_base;
250 }
251 else
252 {
253 _IO_ssize_t cur_size = _IO_str_count(fp);
254 new_pos = EOF;
255
256 /* Move the get pointer, if requested. */
257 if (mode & _IOS_INPUT)
96aa2d94 258 {
2eb45444
UD
259 switch (dir)
260 {
261 case _IO_seek_end:
262 offset += cur_size;
263 break;
264 case _IO_seek_cur:
265 offset += fp->_IO_read_ptr - fp->_IO_read_base;
266 break;
267 default: /* case _IO_seek_set: */
268 break;
269 }
107b8a92
UD
270 if (offset < 0)
271 return EOF;
272 if ((_IO_ssize_t) offset > cur_size
273 && enlarge_userbuf (fp, offset, 1) != 0)
2eb45444
UD
274 return EOF;
275 fp->_IO_read_ptr = fp->_IO_read_base + offset;
276 fp->_IO_read_end = fp->_IO_read_base + cur_size;
277 new_pos = offset;
96aa2d94 278 }
96aa2d94 279
2eb45444
UD
280 /* Move the put pointer, if requested. */
281 if (mode & _IOS_OUTPUT)
96aa2d94 282 {
2eb45444
UD
283 switch (dir)
284 {
285 case _IO_seek_end:
286 offset += cur_size;
287 break;
288 case _IO_seek_cur:
289 offset += fp->_IO_write_ptr - fp->_IO_write_base;
290 break;
291 default: /* case _IO_seek_set: */
292 break;
293 }
107b8a92
UD
294 if (offset < 0)
295 return EOF;
296 if ((_IO_ssize_t) offset > cur_size
297 && enlarge_userbuf (fp, offset, 0) != 0)
2eb45444
UD
298 return EOF;
299 fp->_IO_write_ptr = fp->_IO_write_base + offset;
300 new_pos = offset;
96aa2d94 301 }
96aa2d94
RM
302 }
303 return new_pos;
304}
d18ea0c5 305libc_hidden_def (_IO_str_seekoff)
96aa2d94
RM
306
307int
9dd346ff 308_IO_str_pbackfail (_IO_FILE *fp, int c)
96aa2d94
RM
309{
310 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
311 return EOF;
d18ea0c5 312 return _IO_default_pbackfail (fp, c);
96aa2d94 313}
d18ea0c5 314libc_hidden_def (_IO_str_pbackfail)
96aa2d94
RM
315
316void
9dd346ff 317_IO_str_finish (_IO_FILE *fp, int dummy)
96aa2d94
RM
318{
319 if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
40a55d20 320 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
96aa2d94
RM
321 fp->_IO_buf_base = NULL;
322
d18ea0c5 323 _IO_default_finish (fp, 0);
96aa2d94
RM
324}
325
db3476af 326const struct _IO_jump_t _IO_str_jumps libio_vtable =
40a55d20 327{
96aa2d94
RM
328 JUMP_INIT_DUMMY,
329 JUMP_INIT(finish, _IO_str_finish),
d18ea0c5
AS
330 JUMP_INIT(overflow, _IO_str_overflow),
331 JUMP_INIT(underflow, _IO_str_underflow),
332 JUMP_INIT(uflow, _IO_default_uflow),
333 JUMP_INIT(pbackfail, _IO_str_pbackfail),
334 JUMP_INIT(xsputn, _IO_default_xsputn),
335 JUMP_INIT(xsgetn, _IO_default_xsgetn),
336 JUMP_INIT(seekoff, _IO_str_seekoff),
96aa2d94
RM
337 JUMP_INIT(seekpos, _IO_default_seekpos),
338 JUMP_INIT(setbuf, _IO_default_setbuf),
339 JUMP_INIT(sync, _IO_default_sync),
d18ea0c5 340 JUMP_INIT(doallocate, _IO_default_doallocate),
96aa2d94
RM
341 JUMP_INIT(read, _IO_default_read),
342 JUMP_INIT(write, _IO_default_write),
343 JUMP_INIT(seek, _IO_default_seek),
344 JUMP_INIT(close, _IO_default_close),
dfd2257a
UD
345 JUMP_INIT(stat, _IO_default_stat),
346 JUMP_INIT(showmanyc, _IO_default_showmanyc),
347 JUMP_INIT(imbue, _IO_default_imbue)
96aa2d94 348};