stdio.h (10277B)
1 /* 2 * Copyright (C) 2015-2016 Dimitris Papastamos <sin@2f30.org> 3 * Copyright (C) 2022 q66 <q66@chimera-linux.org> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #ifndef _FORTIFY_STDIO_H 18 #define _FORTIFY_STDIO_H 19 20 #if !defined(__cplusplus) && !defined(__clang__) 21 __extension__ 22 #endif 23 #include_next <stdio.h> 24 25 #if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0 26 #include "fortify-headers.h" 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 #undef fgets 33 #undef fopen 34 #undef fread 35 #undef fwrite 36 #undef vsnprintf 37 #undef vsprintf 38 39 #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ 40 || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ 41 || defined(_BSD_SOURCE) 42 43 #undef fdopen 44 #undef fmemopen 45 #undef popen 46 47 __fh_access(read_only, 2) 48 #if __has_builtin(__builtin_fdopen) 49 __diagnose_as_builtin(__builtin_fdopen, 1, 2) 50 #endif 51 _FORTIFY_FN(fdopen) FILE *fdopen(int __f, const char* _FORTIFY_POS0 __m) 52 { 53 return __orig_fdopen(__f, __m); 54 } 55 56 __fh_malloc(malloc (fclose, 1)) 57 #if __has_builtin(__builtin_fmemopen) 58 __diagnose_as_builtin(__builtin_fmemopen, 1, 2, 3) 59 #endif 60 _FORTIFY_FN(fmemopen) FILE *fmemopen(void* _FORTIFY_POS0 __b, size_t __s, const char* _FORTIFY_POS0 __m) 61 { 62 return __orig_fmemopen(__b, __s, __m); 63 } 64 65 __fh_access(read_only, 1) 66 __fh_access(read_only, 2) 67 __fh_malloc(malloc (pclose, 1)) 68 #if __has_builtin(__builtin_popen) 69 __diagnose_as_builtin(__builtin_popen, 1, 2) 70 #endif 71 _FORTIFY_FN(popen) FILE *popen(const char* _FORTIFY_POS0 __c, const char* _FORTIFY_POS0 __t) 72 { 73 return __orig_popen(__c, __t); 74 } 75 76 #endif /* _POSIX_SOURCE || _POSIX_C_SOURCE || _XOPEN_SOURCE || _GNU_SOURCE || _BSD_SOURCE */ 77 78 __fh_access(write_only, 1, 2) 79 #if __has_builtin(__builtin_fgets) 80 __diagnose_as_builtin(__builtin_fgets, 1, 2, 3) 81 #endif 82 _FORTIFY_FN(fgets) char *fgets(char * _FORTIFY_POS0 __s, int __n, FILE *__f) 83 { 84 __fh_size_t __b = __fh_bos(__s, 0); 85 86 if ((__fh_size_t)__n > __b) 87 __builtin_trap(); 88 return __orig_fgets(__s, __n, __f); 89 } 90 91 __fh_access(read_only, 1) 92 __fh_access(read_only, 2) 93 __fh_malloc(malloc (fclose, 1)) 94 #if __has_builtin(__builtin_fopen) 95 __diagnose_as_builtin(__builtin_fopen, 1, 2) 96 #endif 97 _FORTIFY_FN(fopen) FILE *fopen(const char* _FORTIFY_POS0 __p, const char* _FORTIFY_POS0 __m) 98 { 99 return __orig_fopen(__p, __m); 100 } 101 102 __fh_access(write_only, 1) 103 #if __has_builtin(__builtin_fread) 104 __diagnose_as_builtin(__builtin_fread, 1, 2, 3, 4) 105 #endif 106 _FORTIFY_FN(fread) size_t fread(void * _FORTIFY_POS0 __d, size_t __n, 107 size_t __m, FILE *__f) 108 { 109 __fh_size_t __b = __fh_bos(__d, 0); 110 111 if (__bmo(__n, __m)) 112 __builtin_trap(); 113 if (__n * __m > __b) 114 __builtin_trap(); 115 return __orig_fread(__d, __n, __m, __f); 116 } 117 118 __fh_access(read_only, 1) 119 #if __has_builtin(__builtin_fwrite) 120 __diagnose_as_builtin(__builtin_fwrite, 1, 2, 3, 4) 121 #endif 122 _FORTIFY_FN(fwrite) size_t fwrite(const void * _FORTIFY_POS0 __d, size_t __n, 123 size_t __m, FILE *__f) 124 { 125 __fh_size_t __b = __fh_bos(__d, 0); 126 127 if (__bmo(__n, __m)) 128 __builtin_trap(); 129 if (__n * __m > __b) 130 __builtin_trap(); 131 return __orig_fwrite(__d, __n, __m, __f); 132 } 133 134 #ifndef __clang__ /* FIXME */ 135 #undef tmpfile 136 __fh_malloc(malloc (fclose, 1)) 137 #if __has_builtin(__builtin_tmpfile) 138 __diagnose_as_builtin(__builtin_tmpfile) 139 #endif 140 _FORTIFY_FN(tmpfile) FILE *tmpfile(void) 141 { 142 return __orig_tmpfile(); 143 } 144 #endif 145 146 __fh_access(read_write, 1, 2) 147 __fh_access(read_only, 3) 148 __fh_format(printf, 3, 0) 149 #if __has_builtin(__builtin_vsnprintf) 150 __diagnose_as_builtin(__builtin_vsnprintf, 1, 2, 3, 4) 151 #endif 152 _FORTIFY_FN(vsnprintf) int vsnprintf(char * _FORTIFY_POS0 __s, size_t __n, 153 const char *__f, __builtin_va_list __v) 154 { 155 #if __has_builtin(__builtin___vsnprintf_chk) && USE_NATIVE_CHK 156 return __builtin___vsnprintf_chk(__s, __n, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __v); 157 #else 158 __fh_size_t __b = __fh_bos(__s, 0); 159 160 if (__n > __b) 161 __builtin_trap(); 162 return __orig_vsnprintf(__s, __n, __f, __v); 163 #endif 164 } 165 166 __fh_format(printf, 2, 0) 167 __fh_access(read_write, 1) 168 __fh_access(read_only, 2) 169 #if __has_builtin(__builtin_vsprintf) 170 __diagnose_as_builtin(__builtin_vsprintf, 1, 2, 3) 171 #endif 172 _FORTIFY_FN(vsprintf) int vsprintf(char * _FORTIFY_POS0 __s, const char *__f, 173 __builtin_va_list __v) 174 { 175 #if __has_builtin(__builtin___vsprintf_chk) && USE_NATIVE_CHK 176 return __builtin___vsprintf_chk(__s, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __v); 177 #else 178 __fh_size_t __b = __fh_bos(__s, 0); 179 int __r; 180 181 if (__b != (__fh_size_t)-1) { 182 __r = __orig_vsnprintf(__s, __b, __f, __v); 183 if (__r != -1 && (__fh_size_t)__r >= __b) 184 __builtin_trap(); 185 } else { 186 __r = __orig_vsprintf(__s, __f, __v); 187 } 188 return __r; 189 #endif 190 } 191 192 #ifndef __clang__ /* FIXME */ 193 #undef vfprintf 194 #undef vprintf 195 196 __fh_access(read_only, 2) 197 __fh_format(printf, 2, 0) 198 #if __has_builtin(__builtin_vfprintf) 199 __diagnose_as_builtin(__builtin_vfprintf, 2, 3) 200 #endif 201 _FORTIFY_FN(vfprintf) int vfprintf(FILE * __s, const char *__f, __builtin_va_list __v) 202 { 203 #if __has_builtin(__builtin___vfprintf_chk) && USE_NATIVE_CHK 204 return __builtin___vfprintf_chk(__s, _FORTIFY_SOURCE, __f, __v); 205 #else 206 return __orig_vfprintf(__s, __f, __v); 207 #endif 208 } 209 210 __fh_access(read_only, 1) 211 __fh_format(printf, 1, 0) 212 #if __has_builtin(__builtin_vprintf) 213 __diagnose_as_builtin(__builtin_vprintf, 1, 2) 214 #endif 215 _FORTIFY_FN(vprintf) int vprintf(const char *__f, __builtin_va_list __v) 216 { 217 #if __has_builtin(__builtin___vprintf_chk) && USE_NATIVE_CHK 218 return __builtin___vprintf_chk(_FORTIFY_SOURCE, __f, __v); 219 #else 220 return __orig_vprintf(__f, __v); 221 #endif 222 } 223 224 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) 225 #undef vasprintf 226 #if __has_builtin(__builtin_vasprintf) 227 __diagnose_as_builtin(__builtin_vasprintf, 1, 2, 3) 228 #endif 229 _FORTIFY_FN(vasprintf) int vasprintf(char **restrict strp, const char *restrict fmt, __builtin_va_list ap) 230 { 231 #if __has_builtin(__builtin___vasprintf_chk) && USE_NATIVE_CHK 232 return __builtin___vasprintf_chk(_FORTIFY_SOURCE, strp, fmt, ap); 233 #else 234 int ret = __orig_vasprintf(strp, fmt, ap); 235 if (ret < 0) 236 *strp = NULL; 237 return ret; 238 #endif 239 } 240 241 242 #endif // defined(_GNU_SOURCE) || defined(_BSD_SOURCE) 243 #endif // __clang__ 244 245 246 #if __has_builtin(__builtin_va_arg_pack) 247 248 /* clang is missing __builtin_va_arg_pack, so we cannot use these impls 249 * outside of gcc; we then have a few options: 250 * 251 * 1) using va_start/end and implementing these functions as static inline, 252 * with inlining never happening; that means extra symbols with internal 253 * linkage, which is not ideal 254 * 2) using macros; this is incompatible with c++ and since musl does not 255 * have the __chk variants, we'd need to implement a body with intermediate 256 * variables within the macro, which means more non-portable mess 257 * 3) not implementing these under clang, which is what we do for now 258 * 259 * TODO: add __diagnose_as_builtin 260 */ 261 262 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110834 263 #pragma GCC diagnostic push 264 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 265 266 #undef snprintf 267 #undef sprintf 268 #undef printf 269 #undef fprintf 270 271 __fh_access(read_write, 1, 2) 272 __fh_access(read_only, 3) 273 __fh_format(printf, 3, 4) 274 _FORTIFY_FN(snprintf) int snprintf(char *__s, size_t __n, 275 const char *__f, ...) 276 { 277 #if __has_builtin(__builtin___snprintf_chk) && USE_NATIVE_CHK 278 return __builtin___snprintf_chk(__s, __n, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __builtin_va_arg_pack()); 279 #else 280 __fh_size_t __b = __fh_bos(__s, 0); 281 282 if (__n > __b) 283 __builtin_trap(); 284 return __orig_snprintf(__s, __n, __f, __builtin_va_arg_pack()); 285 #endif 286 } 287 288 __fh_format(printf, 2, 3) 289 __fh_access(read_write, 1) 290 __fh_access(read_only, 2) 291 _FORTIFY_FN(sprintf) int sprintf(char *__s, const char *__f, ...) 292 { 293 #if __has_builtin(__builtin___sprintf_chk) && USE_NATIVE_CHK 294 return __builtin___sprintf_chk(__s, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __builtin_va_arg_pack()); 295 #else 296 __fh_size_t __b = __fh_bos(__s, 0); 297 int __r; 298 299 if (__b != (__fh_size_t)-1) { 300 __r = __orig_snprintf(__s, __b, __f, __builtin_va_arg_pack()); 301 if (__r != -1 && (__fh_size_t)__r >= __b) 302 __builtin_trap(); 303 } else { 304 __r = __orig_sprintf(__s, __f, __builtin_va_arg_pack()); 305 } 306 return __r; 307 #endif 308 } 309 310 __fh_format(printf, 1, 2) 311 __fh_access(read_only, 1) 312 _FORTIFY_FN(printf) int printf(const char *__f, ...) 313 { 314 #if __has_builtin(__builtin___printf_chk) && USE_NATIVE_CHK 315 return __builtin___printf_chk(_FORTIFY_SOURCE, __f, __builtin_va_arg_pack()); 316 #else 317 return __orig_printf(__f, __builtin_va_arg_pack()); 318 #endif 319 } 320 321 __fh_access(read_only, 2) 322 __fh_format(printf, 2, 0) 323 #if __has_builtin(__builtin_fprintf) 324 __diagnose_as_builtin(__builtin_fprintf, 2, 3) 325 #endif 326 _FORTIFY_FN(fprintf) int fprintf(FILE *__s, const char *__f, ...) 327 { 328 #if __has_builtin(__builtin___fprintf_chk) && USE_NATIVE_CHK 329 return __builtin___fprintf_chk(_FORTIFY_SOURCE, __s, __f, __builtin_va_arg_pack()); 330 #else 331 return __orig_fprintf(__s, __f, __builtin_va_arg_pack()); 332 #endif 333 } 334 335 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) 336 #ifndef __clang__ 337 #undef asprintf 338 __fh_access(read_only, 2) 339 __fh_format(printf, 2, 0) 340 #if __has_builtin(__builtin_asprintf) 341 __diagnose_as_builtin(__builtin_asprintf, 2, 3) 342 #endif 343 _FORTIFY_FN(asprintf) int asprintf(char **restrict strp, const char *restrict fmt, ...) 344 { 345 #if __has_builtin(__builtin___asprintf_chk) && USE_NATIVE_CHK 346 return __builtin___asprintf_chk(_FORTIFY_SOURCE, strp, fmt, __builtin_va_arg_pack()); 347 #else 348 int ret = __orig_asprintf(strp, fmt, __builtin_va_arg_pack()); 349 if (ret<0) 350 *strp = NULL; 351 return ret; 352 #endif 353 } 354 #endif // __clang__ 355 #endif 356 357 #pragma GCC diagnostic pop 358 #endif /* __has_builtin(__builtin_va_arg_pack) */ 359 360 #ifdef __cplusplus 361 } 362 #endif 363 364 #endif 365 366 #endif