checkedc / checkedc-llvm-project

This was a fork of Checked C clang used from 2021-2024. The changes have been merged into the original Checked C clang repo, which is now at https://github.com/checkedc/checkedc-clang.
https://www.checkedc.org
13 stars 19 forks source link

Memset bounds safe interface: char vs uint8 #539

Open secure-sw-dev-bot opened 2 years ago

secure-sw-dev-bot commented 2 years ago

This issue was copied from https://github.com/microsoft/checkedc-clang/issues/540


When calling memset on an array_ptr, the checkedc-clang will be unable to "prove argument meets declared bounds", saying that: expected bounds: bounds((array_ptr<char>)dst, (array_ptr<char>)dst + len) and inferred bounds: bounds(dst, dst + len). To remove the warning, the array_ptr needs to be explicitly cast to an array_ptr. Our bounds safe interface uses array_ptr in its description of the bounds for memset (since pointer arithmetic on void pointers doesn't make sense), but it seems a bit confusing to force an equivalently sized type to cast to char in order to compile memset.

From line 428 in clang\lib\AST\CanonBounds.cpp:
       // TODO: consider treating operations whose types differ
       // but that still produce the same value as being the
       // same.  For example:
       // - Pointer arithmetic where the pointer referent types are the same
       //   size, checkedness is the same, and the integer types are the
       //    same size/signedness. 

According to the internet, the signedness of char isn't properly specified in c but char is treated as signed by default by gcc and MSVC (but unsigned in at least some versions of Android). Therefore I'm not sure whether the comment above applies in this case; however it still seems that memset should not require the explicit cast to array_ptr.

secure-sw-dev-bot commented 2 years ago

Comment from @dtarditi:

This is due to missing functionality when comparing bounds expressions for equivalence. We check that the subexpressions of the bounds expressions are equivalence. When checking pointer arithmetic expressions for equivalence, we check that the types of arguments are identical and that the corresponding operands are equivalent. The check on types is too strict. For the pointer-typed operands, we only need to check that the referent types of the pointer types have the same size . For the integer-typed operands, we only need to check that they have the same signedness.