syslog: Improve fortify with clang
[glibc.git] / libio / strops.c
blob9f66186ac20c33c03bd1e1e3958d0a98e5d8553f
1 /* Copyright (C) 1993-2024 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, see
16 <https://www.gnu.org/licenses/>.
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. */
27 #include <assert.h>
28 #include "strfile.h"
29 #include "libioP.h"
30 #include <string.h>
31 #include <stdio_ext.h>
33 void
34 _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, size_t size,
35 char *pstart)
37 FILE *fp = &sf->_sbf._f;
38 char *end;
40 if (size == 0)
41 end = strchr (ptr, '\0');
42 else if ((size_t) ptr + size > (size_t) ptr)
43 end = ptr + size;
44 else
45 end = (char *) -1;
46 _IO_setb (fp, ptr, end, 0);
48 fp->_IO_write_base = ptr;
49 fp->_IO_read_base = ptr;
50 fp->_IO_read_ptr = ptr;
51 if (pstart)
53 fp->_IO_write_ptr = pstart;
54 fp->_IO_write_end = end;
55 fp->_IO_read_end = pstart;
57 else
59 fp->_IO_write_ptr = ptr;
60 fp->_IO_write_end = ptr;
61 fp->_IO_read_end = end;
63 /* A null _allocate_buffer function flags the strfile as being static. */
64 sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
67 void
68 _IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
70 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
73 void
74 _IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
76 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
77 sf->_sbf._f._flags |= _IO_NO_WRITES;
80 int
81 _IO_str_overflow (FILE *fp, int c)
83 int flush_only = c == EOF;
84 size_t pos;
85 if (fp->_flags & _IO_NO_WRITES)
86 return flush_only ? 0 : EOF;
87 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
89 fp->_flags |= _IO_CURRENTLY_PUTTING;
90 fp->_IO_write_ptr = fp->_IO_read_ptr;
91 fp->_IO_read_ptr = fp->_IO_read_end;
93 pos = fp->_IO_write_ptr - fp->_IO_write_base;
94 if (pos >= (size_t) (_IO_blen (fp) + flush_only))
96 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
97 return EOF;
98 else
100 char *new_buf;
101 char *old_buf = fp->_IO_buf_base;
102 size_t old_blen = _IO_blen (fp);
103 size_t new_size = 2 * old_blen + 100;
104 if (new_size < old_blen)
105 return EOF;
106 new_buf = malloc (new_size);
107 if (new_buf == NULL)
109 /* __ferror(fp) = 1; */
110 return EOF;
112 if (old_buf)
114 memcpy (new_buf, old_buf, old_blen);
115 free (old_buf);
116 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
117 fp->_IO_buf_base = NULL;
119 memset (new_buf + old_blen, '\0', new_size - old_blen);
121 _IO_setb (fp, new_buf, new_buf + new_size, 1);
122 fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
123 fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
124 fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
125 fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
127 fp->_IO_write_base = new_buf;
128 fp->_IO_write_end = fp->_IO_buf_end;
132 if (!flush_only)
133 *fp->_IO_write_ptr++ = (unsigned char) c;
134 if (fp->_IO_write_ptr > fp->_IO_read_end)
135 fp->_IO_read_end = fp->_IO_write_ptr;
136 if (flush_only)
137 return 0;
138 else
139 return c;
141 libc_hidden_def (_IO_str_overflow)
144 _IO_str_underflow (FILE *fp)
146 if (fp->_IO_write_ptr > fp->_IO_read_end)
147 fp->_IO_read_end = fp->_IO_write_ptr;
148 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
150 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
151 fp->_IO_read_ptr = fp->_IO_write_ptr;
152 fp->_IO_write_ptr = fp->_IO_write_end;
154 if (fp->_IO_read_ptr < fp->_IO_read_end)
155 return *((unsigned char *) fp->_IO_read_ptr);
156 else
157 return EOF;
159 libc_hidden_def (_IO_str_underflow)
161 /* The size of the valid part of the buffer. */
163 ssize_t
164 _IO_str_count (FILE *fp)
166 return ((fp->_IO_write_ptr > fp->_IO_read_end
167 ? fp->_IO_write_ptr : fp->_IO_read_end)
168 - fp->_IO_read_base);
172 static int
173 enlarge_userbuf (FILE *fp, off64_t offset, int reading)
175 if ((ssize_t) offset <= _IO_blen (fp))
176 return 0;
178 ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
180 /* Try to enlarge the buffer. */
181 if (fp->_flags & _IO_USER_BUF)
182 /* User-provided buffer. */
183 return 1;
185 size_t newsize = offset + 100;
186 char *oldbuf = fp->_IO_buf_base;
187 char *newbuf = malloc (newsize);
188 if (newbuf == NULL)
189 return 1;
191 if (oldbuf != NULL)
193 memcpy (newbuf, oldbuf, _IO_blen (fp));
194 free (oldbuf);
195 /* Make sure _IO_setb won't try to delete
196 _IO_buf_base. */
197 fp->_IO_buf_base = NULL;
200 _IO_setb (fp, newbuf, newbuf + newsize, 1);
202 if (reading)
204 fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
205 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
206 fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
207 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
209 fp->_IO_read_base = newbuf;
210 fp->_IO_read_end = fp->_IO_buf_end;
212 else
214 fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
215 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
216 fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
217 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
219 fp->_IO_write_base = newbuf;
220 fp->_IO_write_end = fp->_IO_buf_end;
223 /* Clear the area between the last write position and th
224 new position. */
225 assert (offset >= oldend);
226 if (reading)
227 memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
228 else
229 memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
231 return 0;
234 static void
235 _IO_str_switch_to_get_mode (FILE *fp)
237 if (_IO_in_backup (fp))
238 fp->_IO_read_base = fp->_IO_backup_base;
239 else
241 fp->_IO_read_base = fp->_IO_buf_base;
242 if (fp->_IO_write_ptr > fp->_IO_read_end)
243 fp->_IO_read_end = fp->_IO_write_ptr;
245 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
247 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
250 off64_t
251 _IO_str_seekoff (FILE *fp, off64_t offset, int dir, int mode)
253 off64_t new_pos;
255 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
256 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
258 bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
259 || _IO_in_put_mode (fp));
260 if (was_writing)
261 _IO_str_switch_to_get_mode (fp);
263 if (mode == 0)
265 new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
267 else
269 ssize_t cur_size = _IO_str_count(fp);
270 new_pos = EOF;
272 /* Move the get pointer, if requested. */
273 if (mode & _IOS_INPUT)
275 ssize_t base;
276 switch (dir)
278 case _IO_seek_set:
279 base = 0;
280 break;
281 case _IO_seek_cur:
282 base = fp->_IO_read_ptr - fp->_IO_read_base;
283 break;
284 default: /* case _IO_seek_end: */
285 base = cur_size;
286 break;
288 ssize_t maxval = SSIZE_MAX - base;
289 if (offset < -base || offset > maxval)
291 __set_errno (EINVAL);
292 return EOF;
294 base += offset;
295 if (base > cur_size
296 && enlarge_userbuf (fp, base, 1) != 0)
297 return EOF;
298 fp->_IO_read_ptr = fp->_IO_read_base + base;
299 fp->_IO_read_end = fp->_IO_read_base + cur_size;
300 new_pos = base;
303 /* Move the put pointer, if requested. */
304 if (mode & _IOS_OUTPUT)
306 ssize_t base;
307 switch (dir)
309 case _IO_seek_set:
310 base = 0;
311 break;
312 case _IO_seek_cur:
313 base = fp->_IO_write_ptr - fp->_IO_write_base;
314 break;
315 default: /* case _IO_seek_end: */
316 base = cur_size;
317 break;
319 ssize_t maxval = SSIZE_MAX - base;
320 if (offset < -base || offset > maxval)
322 __set_errno (EINVAL);
323 return EOF;
325 base += offset;
326 if (base > cur_size
327 && enlarge_userbuf (fp, base, 0) != 0)
328 return EOF;
329 fp->_IO_write_ptr = fp->_IO_write_base + base;
330 new_pos = base;
333 return new_pos;
335 libc_hidden_def (_IO_str_seekoff)
338 _IO_str_pbackfail (FILE *fp, int c)
340 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
341 return EOF;
342 return _IO_default_pbackfail (fp, c);
344 libc_hidden_def (_IO_str_pbackfail)
346 void
347 _IO_str_finish (FILE *fp, int dummy)
349 if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
350 free (fp->_IO_buf_base);
351 fp->_IO_buf_base = NULL;
353 _IO_default_finish (fp, 0);