Add _FORTIFY_SOURCE support for string.h and stdio.h (#234)

This adds the fortified declarations, in line with the specifications within clang and the gcc documentation here: https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Object-Size-Checking.html#Object-Size-Checking

This simplifies the checks for fortify source, and makes the tests more robust.

There is also the addition of a posix header, unistd.h, as a stopgap measure.

Tested: Mac OS X, Linux, Windows.
This commit is contained in:
Sam Elliott 2017-11-07 09:47:21 -08:00 коммит произвёл GitHub
Родитель 261aacbce9
Коммит f534fb22e8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 215 добавлений и 43 удалений

Просмотреть файл

@ -12,24 +12,47 @@
#include "_builtin_common.h"
#if _USE_FORTIFY_LEVEL > 0
#ifndef __has_builtin
#define _undef__has_builtin
#define __has_builtin(x) 0
#endif
#if __has_builtin(__builtin___snprintf_chk) || defined(__GNUC__)
#if __has_builtin(__builtin___sprintf_chk) || defined(__GNUC__)
// sprintf
extern _Unchecked
int __snprintf_chk(char * __restrict s : count(n),
size_t n,
int flag,
size_t obj_size,
const char * __restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
int __sprintf_chk(char * restrict buffer : itype(restrict _Nt_array_ptr<char>),
int flag,
size_t obj_size,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
_Unchecked
int __builtin___snprintf_chk(char * restrict s : count(n),
size_t n,
int __builtin___sprintf_chk(char * restrict buffer : itype(restrict _Nt_array_ptr<char>),
int flag,
size_t obj_size,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
#endif
#if __has_builtin(__builtin___snprintf_chk) || defined(__GNUC__)
// snprintf
extern _Unchecked
int __snprintf_chk(char * restrict buffer : count(maxlen),
size_t maxlen,
int flag,
size_t obj_size,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
_Unchecked
int __builtin___snprintf_chk(char * restrict buffer : count(maxlen),
size_t maxlen,
int flag,
size_t obj_size,
const char * restrict format :
@ -38,20 +61,41 @@ int __builtin___snprintf_chk(char * restrict s : count(n),
...);
#endif
#if __has_builtin(__builtin___vsnprintf_chk) || defined(__GNUC__)
#if __has_builtin(__builtin___vsprintf_chk) || defined(__GNUC__)
// vsprintf
extern _Unchecked
int __vsnprintf_chk(char * __restrict s : count(n),
size_t n,
int flag,
size_t obj_size,
const char * __restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
int __vsprintf_chk(char * restrict buffer : itype(restrict _Nt_array_ptr<char>),
int flag,
size_t obj_size,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
_Unchecked
int __builtin___vsnprintf_chk(char * restrict s : count(n),
size_t n,
int __builtin___vsprintf_chk(char * restrict buffer : itype(restrict _Nt_array_ptr<char>),
int flag,
size_t obj_size,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list arg);
#endif
#if __has_builtin(__builtin___vsnprintf_chk) || defined(__GNUC__)
// vsnprintf
extern _Unchecked
int __vsnprintf_chk(char * restrict buffer : count(maxlen),
size_t maxlen,
int flag,
size_t obj_size,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
_Unchecked
int __builtin___vsnprintf_chk(char * restrict buffer : count(maxlen),
size_t maxlen,
int flag,
size_t obj_size,
const char * restrict format :
@ -59,7 +103,73 @@ int __builtin___vsnprintf_chk(char * restrict s : count(n),
va_list arg);
#endif
#if __has_builtin(__builtin___fprintf_chk) || defined(__GNUC__)
// fprintf
extern _Unchecked
int __fprintf_chk(FILE * restrict stream : itype(restrict _Ptr<FILE>),
int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
_Unchecked
int __builtin___fprintf_chk(FILE * restrict stream : itype(restrict _Ptr<FILE>),
int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
#endif
#if __has_builtin(__builtin___printf_chk) || defined(__GNUC__)
// printf
extern _Unchecked
int __printf_chk(int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
_Unchecked
int __builtin___printf_chk(int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
...);
#endif
#if __has_builtin(__builtin___vfprintf_chk) || defined(__GNUC__)
// vfprintf
extern _Unchecked
int __vfprintf_chk(FILE * restrict stream : itype(restrict _Ptr<FILE>),
int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
_Unchecked
int __builtin___vfprintf_chk(FILE * restrict stream : itype(restrict _Ptr<FILE>),
int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
#endif
#if __has_builtin(__builtin___vprintf_chk) || defined(__GNUC__)
// vprintf
extern _Unchecked
int __vprintf_chk(int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
_Unchecked
int __builtin___vprintf_chk(int flag,
const char * restrict format :
itype(restrict _Nt_array_ptr<const char>),
va_list);
#endif
#ifdef _undef__has_builtin
#undef _undef__has_builtin
#undef __has_builtin
#endif
#endif

Просмотреть файл

@ -12,6 +12,8 @@
#include "_builtin_common.h"
#if _USE_FORTIFY_LEVEL > 0
#ifndef __has_builtin
#define _undef__has_builtin
#define __has_builtin(x) 0
@ -38,6 +40,24 @@ void *__builtin___memset_chk(void * s : byte_count(n),
size_t obj_size) : bounds(s, (_Array_ptr<char>) s + n);
#endif
#if __has_builtin(__builtin___strcat_chk) || defined(__GNUC__)
// Left Unchecked Intentionally. See comment in string_checked.h
_Unchecked
char *__builtin___strcat_chk(char * restrict dest,
const char * restrict src :
itype(restrict _Nt_array_ptr<const char>),
size_t obj_size);
#endif
#if __has_builtin(__builtin___strcpy_chk) || defined(__GNUC__)
// Left Unchecked Intentionally. See comment in string_checked.h
_Unchecked
char *__builtin___strcpy_chk(char * restrict dest,
const char * restrict src :
itype(restrict _Nt_array_ptr<const char>),
size_t obj_size);
#endif
#if __has_builtin(__builtin___strncat_chk) || defined(__GNUC__)
// TODO: we have no way to express the bounds requirement on dest,
// which needs to be count(strlen(dest) + n).
@ -59,3 +79,5 @@ char *__builtin___strncpy_chk(char * restrict dest : count(n),
#undef _undef__has_builtin
#undef __has_builtin
#endif
#endif

Просмотреть файл

@ -50,60 +50,74 @@ int setvbuf(FILE * restrict stream : itype(restrict _Ptr<FILE>),
// * Any pointer arguments may not meet the requirements of the
// format string.
//
#if _FORTIFY_SOURCE == 0
_Unchecked
int fprintf(FILE * restrict stream : itype(restrict _Ptr<FILE>),
const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#endif
_Unchecked
int fscanf(FILE * restrict stream : itype(restrict _Ptr<FILE>),
const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#if _FORTIFY_SOURCE == 0
_Unchecked
int printf(const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#endif
_Unchecked
int scanf(const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#if _FORTIFY_SOURCE == 0
// The output buffer parameter s is an unchecked pointer because no bounds are provided.
_Unchecked
int sprintf(char * restrict s,
const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#endif
_Unchecked
int sscanf(const char * restrict s : itype(restrict _Nt_array_ptr<const char>),
const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
// TODO: Apple System Headers Support
#if !defined (__APPLE__) && _FORTIFY_SOURCE > 0
#if _FORTIFY_SOURCE == 0
_Unchecked
int snprintf(char * restrict s : count(n), size_t n,
const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#endif
_Unchecked
int vfprintf(FILE * restrict stream : itype(restrict _Ptr<FILE>),
const char * restrict format : itype(restrict _Nt_array_ptr<const char>),
va_list arg);
#endif
_Unchecked
int vfscanf(FILE * restrict stream : itype(restrict _Ptr<FILE>),
const char * restrict format : itype(restrict _Nt_array_ptr<const char>),
va_list arg);
#if _FORTIFY_SOURCE == 0
_Unchecked
int vprintf(const char * restrict format : itype(restrict _Nt_array_ptr<const char>),
va_list arg);
#endif
_Unchecked
int vscanf(const char * restrict format : itype(restrict _Nt_array_ptr<const char>),
va_list arg);
// TODO: Apple System Headers Support
#if !defined (__APPLE__) && _FORTIFY_SOURCE > 0
#if _FORTIFY_SOURCE == 0
_Unchecked
int vsnprintf(char * restrict s : count(n), size_t n,
const char * restrict format,
va_list arg);
#endif
// The output buffer parameter has an unchecked pointer type becuse it is missing bounds.
_Unchecked
int vsprintf(char * restrict s,
const char * restrict format : itype(restrict _Nt_array_ptr<const char>),
va_list arg);
#endif
_Unchecked
int vsscanf(const char * restrict s : itype(restrict _Nt_array_ptr<const char>),
const char * restrict format : itype(restrict _Nt_array_ptr<const char>),

Просмотреть файл

@ -35,8 +35,7 @@
#undef strspn
#endif
// TODO: Apple System Headers Support
#if !( defined(__APPLE__) && _FORTIFY_SOURCE > 0)
#if _FORTIFY_SOURCE == 0
void *memcpy(void * restrict dest : byte_count(n),
const void * restrict src : byte_count(n),
size_t n) : bounds(dest, (_Array_ptr<char>) dest + n);
@ -44,20 +43,21 @@ void *memcpy(void * restrict dest : byte_count(n),
void *memmove(void * restrict dest : byte_count(n),
const void * restrict src : byte_count(n),
size_t n) : bounds(dest, (_Array_ptr<char>)dest + n);
#endif
void *memset(void * dest : byte_count(n),
int c,
size_t n) : bounds(dest, (_Array_ptr<char>)dest + n);
// Dest is left unchecked intentionally. There is no bound on dest, so this
// is always an unchecked function
_Unchecked
char *strcpy(char * restrict s1,
const char * restrict s2 : itype(restrict _Nt_array_ptr<const char>));
char *strcpy(char * restrict dest,
const char * restrict src : itype(restrict _Nt_array_ptr<const char>));
// TODO: Apple System Headers Support
#if !( defined(__APPLE__) && _FORTIFY_SOURCE > 0)
char *strncpy(char * restrict dest : count(n),
const char * restrict src : count(n),
size_t n) : bounds(dest, (_Array_ptr<char>)dest + n);
#endif
// Dest is left unchecked intentionally. There is no bound on dest, so this
// is always an unchecked function.
@ -65,8 +65,6 @@ _Unchecked
char *strcat(char * restrict dest,
const char * restrict src : itype(restrict _Nt_array_ptr<const char>));
// TODO: Apple System Headers Support
#if !( defined(__APPLE__) && _FORTIFY_SOURCE > 0)
// TODO: we have no way to express the bounds requirement on dest,
// which needs to be count(strlen(dest) + n).
_Unchecked
@ -114,12 +112,6 @@ char *strtok(char * restrict s1 : itype(restrict _Nt_array_ptr<char>),
const char * restrict s2 : itype(restrict _Nt_array_ptr<const char>)) :
itype(_Nt_array_ptr<char>);
// TODO: Apple System Headers Support
#if !( defined(__APPLE__) && _FORTIFY_SOURCE > 0)
void *memset(void *s : byte_count(n), int c, size_t n) :
bounds(s, (_Array_ptr<char>) s + n);
#endif
char *strerror(int errnum) : itype(_Nt_array_ptr<char>);
size_t strlen(const char *s : itype(_Nt_array_ptr<const char>));

18
include/unistd_checked.h Normal file
Просмотреть файл

@ -0,0 +1,18 @@
//---------------------------------------------------------------------//
// Bounds-safe interfaces for functions in unistd.h that //
// take pointer arguments. //
// //
// These are POSIX-only //
/////////////////////////////////////////////////////////////////////////
#include <unistd.h>
#pragma BOUNDS_CHECKED ON
#if _POSIX_VERSION >= 200112L
extern char ** environ : itype(_Nt_array_ptr<_Nt_array_ptr<char>>);
#endif
#pragma BOUNDS_CHECKED OFF

Просмотреть файл

@ -4,7 +4,11 @@
// The following lines are for the LLVM test harness:
//
// RUN: %clang -fcheckedc-extension -fsyntax-only %s
// RUN: %clang -fcheckedc-extension -fsyntax-only -D_FORTIFY_SOURCE=0 %s
// RUN: %clang -fcheckedc-extension -fsyntax-only -D_FORTIFY_SOURCE=1 %s
// RUN: %clang -fcheckedc-extension -fsyntax-only -D_FORTIFY_SOURCE=2 %s
// C Standard
#include "../../include/fenv_checked.h"
#include "../../include/inttypes_checked.h"
#include "../../include/math_checked.h"
@ -15,3 +19,15 @@
#define _CHECKEDC_MOCKUP_THREADS 1
#include "../../include/threads_checked.h"
#include "../../include/time_checked.h"
// Posix Headers
//
// Uses clang-specific __has_include macro to detect unistd.h
// which is required by Posix Standard.
#if defined(__has_include)
#if __has_include(<unistd.h>)
#include "../../include/unistd_checked.h"
#endif
#endif