Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 6 commits into from
Jun 11, 2021
23 changes: 18 additions & 5 deletions include/checkedc_extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// choose to use these over the default bounds-safe interfaces. //
//////////////////////////////////////////////////////////////////////////////

#include <stdarg.h>
#include <stdlib_checked.h>
#include <string_checked.h>

Expand All @@ -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<char>) 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<char>) count(n),
size_t n,
const char * restrict format : itype(restrict _Nt_array_ptr<const char>),
...);
...) {
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<char> count(n) whose corresponding parameter has the type
// _Nt_array_ptr<char> count(n-1).
snprintf(s, n, format, argptr);
va_end(argptr);
}

#pragma CHECKED_SCOPE pop

Expand Down
6 changes: 4 additions & 2 deletions include/stdio_checked.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int setvbuf(FILE * restrict stream : itype(restrict _Ptr<FILE>),
// - Fortifying, No Macro: we need the definition
// - Not Fortifying, No Macro: we need the definition


#if _FORTIFY_SOURCE == 0 || !defined(fprintf)
#undef fprintf
_Unchecked
Expand Down Expand Up @@ -113,9 +114,10 @@ int sscanf(const char * restrict s : itype(restrict _Nt_array_ptr<const char>),
// 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<char>) count(n == 0 ? 0 : n-1),
size_t n,
int snprintf(char * restrict s : itype(restrict _Nt_array_ptr<char>) count(n-1),
size_t n _Where n > 0,
const char * restrict format : itype(restrict _Nt_array_ptr<const char>), ...);
#endif

Expand Down
67 changes: 67 additions & 0 deletions tests/dynamic_checking/checked_headers/ext.c
Original file line number Diff line number Diff line change
@@ -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 <checkedc_extensions.h>
#include <stddef.h>
#include <stdio.h>

// 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<char>) count(n-1),
size_t n _Where n > 0,
const char * restrict src : itype(restrict _Nt_array_ptr<const char>)) {
return;
}


void iface_array_ptr(char * restrict s : itype(restrict _Array_ptr<char>) count(n),
size_t n,
const char * restrict src : itype(restrict _Array_ptr<const char>)) {
// Enclosing the call to iface in an unchecked block to be able to pass an
// argument of type _Array_ptr<char> and bounds count(n) whose corresponding
// parameter has the interface type _Nt_array_ptr<char> and bounds count(n-1).
// This avoids the compiler error: passing '_Array_ptr<char> restrict' to
// parameter of incompatible type '_Nt_array_ptr<char>'.
_Unchecked{ iface(s, n, src); }
}



void iface_test1(_Array_ptr<char> 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<char> 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<char> 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);}
}