Skip to content

Commit

Permalink
Fixes for errors in the "array_ptr" interfaces to some libc functions…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
sulekhark committed Jun 11, 2021
1 parent 251cf68 commit 6b4a3a2
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 7 deletions.
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);}
}

0 comments on commit 6b4a3a2

Please sign in to comment.