From 6b4a3a2bd364c47a6bad2ac6201cc2ca99aa84a0 Mon Sep 17 00:00:00 2001 From: Sulekha Kulkarni Date: Fri, 11 Jun 2021 14:25:14 -0700 Subject: [PATCH] Fixes for errors in the "array_ptr" interfaces to some libc functions declared in checkedc_extensions.h, and removal of the conditional in the snprintf declaration in stdio_checked.h (#456) * Modified some of the Checked-C-specific declarations of libc functions to address the issues raised in #499 and #450 * Missed adding the modified header files. * Added the _Where clause to more closely resemble the snprintf declaration. * Improvements to the test case. * Incorporated review comments. --- include/checkedc_extensions.h | 23 +++++-- include/stdio_checked.h | 6 +- tests/dynamic_checking/checked_headers/ext.c | 67 ++++++++++++++++++++ 3 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 tests/dynamic_checking/checked_headers/ext.c diff --git a/include/checkedc_extensions.h b/include/checkedc_extensions.h index 568d7e79f8..ea8ebc3319 100644 --- a/include/checkedc_extensions.h +++ b/include/checkedc_extensions.h @@ -4,6 +4,7 @@ // choose to use these over the default bounds-safe interfaces. // ////////////////////////////////////////////////////////////////////////////// +#include #include #include @@ -17,17 +18,29 @@ // default strncmp has a bounds-safe interface nt_array_ptr; // this option is for array_ptr -extern inline int strncmp_array_ptr(const char *src : count(n), const char *s2 : count(n), size_t n) { +inline int __attribute__((__always_inline__)) +strncmp_array_ptr(const char *src : count(n), const char *s2 : count(n), size_t n) { _Unchecked { return strncmp(src, s2, n); } } // default snprintf assumes nt_array_ptr for bounds-safe interface // this option is for array_ptr -_Unchecked -int snprintf_array_ptr(char * restrict s : itype(restrict _Array_ptr) count(n), - size_t n, +// clang does not inline functions that use va_list/va_start/va_end to +// access variable number of arguments. +_Unchecked static int +snprintf_array_ptr(char * restrict s : itype(restrict _Array_ptr) count(n), + size_t n, const char * restrict format : itype(restrict _Nt_array_ptr), - ...); + ...) { + va_list argptr; + va_start(argptr, format); + // The call to snprintf needs to be in an unchecked block as the compiler, + // in checked scope, will not allow passing an argument of type + // _Array_ptr count(n) whose corresponding parameter has the type + // _Nt_array_ptr count(n-1). + snprintf(s, n, format, argptr); + va_end(argptr); +} #pragma CHECKED_SCOPE pop diff --git a/include/stdio_checked.h b/include/stdio_checked.h index cf260a0229..2c75e0d0a4 100644 --- a/include/stdio_checked.h +++ b/include/stdio_checked.h @@ -74,6 +74,7 @@ int setvbuf(FILE * restrict stream : itype(restrict _Ptr), // - Fortifying, No Macro: we need the definition // - Not Fortifying, No Macro: we need the definition + #if _FORTIFY_SOURCE == 0 || !defined(fprintf) #undef fprintf _Unchecked @@ -113,9 +114,10 @@ int sscanf(const char * restrict s : itype(restrict _Nt_array_ptr), // and counts that number in n, s only needs count(n-1) per the // definition of _Nt types. Additional declaration for arrays // available in checkedc_extensions.h + _Unchecked -int snprintf(char * restrict s : itype(restrict _Nt_array_ptr) count(n == 0 ? 0 : n-1), - size_t n, +int snprintf(char * restrict s : itype(restrict _Nt_array_ptr) count(n-1), + size_t n _Where n > 0, const char * restrict format : itype(restrict _Nt_array_ptr), ...); #endif diff --git a/tests/dynamic_checking/checked_headers/ext.c b/tests/dynamic_checking/checked_headers/ext.c new file mode 100644 index 0000000000..6841f5a88a --- /dev/null +++ b/tests/dynamic_checking/checked_headers/ext.c @@ -0,0 +1,67 @@ +// Tests for calling functions declared in checkedc_extensions.h +// +// The following lines are for the LLVM test harness: +// +// RUN: %clang -o %t.exe %s %checkedc_target_flags +// RUN: %checkedc_rununder %t.exe + +// expected-no-diagnostics + +#pragma CHECKED_SCOPE on + +#include +#include +#include + +// A function with an interface similar to snprintf but without the variable +// number of arguments. The purpose is to test such a call interface in checked +// scope. +void iface(char * restrict s : itype(restrict _Nt_array_ptr) count(n-1), + size_t n _Where n > 0, + const char * restrict src : itype(restrict _Nt_array_ptr)) { + return; +} + + +void iface_array_ptr(char * restrict s : itype(restrict _Array_ptr) count(n), + size_t n, + const char * restrict src : itype(restrict _Array_ptr)) { + // Enclosing the call to iface in an unchecked block to be able to pass an + // argument of type _Array_ptr and bounds count(n) whose corresponding + // parameter has the interface type _Nt_array_ptr and bounds count(n-1). + // This avoids the compiler error: passing '_Array_ptr restrict' to + // parameter of incompatible type '_Nt_array_ptr'. + _Unchecked{ iface(s, n, src); } +} + + + +void iface_test1(_Array_ptr p : count(len), size_t len) { + + char buf _Checked[50]; + iface_array_ptr(buf, 50, "Hello world"); + iface_array_ptr(buf, 0, "Hello world"); + + iface_array_ptr(p, len, "Hello world"); + iface_array_ptr(p, 0, "Hello world"); +} + +void iface_test2(_Nt_array_ptr p : count(len), size_t len) { + char buf _Nt_checked[50]; + iface(buf, 50, "Hello world"); + + iface(p, len + 1, "Hello world"); +} + +void test3(_Array_ptr buf : count(len), size_t len) { + _Unchecked{ snprintf_array_ptr(buf, len, "Hello world - 3"); } +} + +int main(void) { + char buf _Checked[50]; + test3(buf, 50) ; + char buf1 _Checked[50]; + test3(buf1, 50) ; + int res = strncmp_array_ptr(buf, buf1, 50); + _Unchecked {printf("res: %d buf: %s buf1: %s\n", res, buf, buf1);} +}