[C-safe-secure-studygroup] reframing rule 11.6 to focus on undefined behavior

Fulvio Baccaglini fbaccaglini at perforce.com
Wed Oct 10 13:13:49 BST 2018


On Sat, 2018-10-06 at 11:26 -0600, Martin Sebor wrote:
> ...
> 
> Note the use of the word /may/ in the first two paragraphs: /may
> result/ and /may produce/.  I.e., violating the rule does not
> necessarily result in undefined behavior.
> 
> The obvious problem with 11.6, as with many other similarly
> formulated rules, is that it disregards all the valid and
> safe uses cases in favor of simplicity of specification.  That
> inevitably leads to false positives (if we use the common sense
> definition of the term).
> 
> For example:
> 
>    1) Conversions to intptr_t that don't convert the result back
>       to a pointer type.  We discussed a number of use cases for
>       this in wide-spread practice, such as pointer hashing.
> 
>    2) Conversions to intptr_t and back that preserve the pointer
>       value of the converted value.  For example:
> 
>       extern int *p;
>       uintptr_t i = (uintptr_t)p;   // safe by definition
>       p = (int*)i;                  // ditto
> 
>    3) Conversions to _Bool which are well-defined.

The Rationale of Rule 11.6 only focuses on undefined behaviour, and its
source references also refer to implementation defined behaviour, which
is also covered by Dir 1.1.

Even if not explicitly stated, I personally think that there is more to
Rule 11.6 (and also some other MISRA guidelines), than avoding these
behaviours, as software defects can also be associated with e.g.
unintended behaviour.

Casting could be seen as a way to bypass the restrictions of C's
abstract types, and it can be argued that in a sense casting represents
a declaration by developers that they intend to further weaken the C
type system, to gain access to additional machine-level information
over and above the logical information that forms the definition of the
type.

It could be argued that in these cases the C language says: "do you
really want to bypass the restrictions of abstract types? if so please
declare that this is what you want to do", while MISRA C says: "do you
really want to bypass the restrictions of abstract types? if so please
explain why you what to do it".

In this example:

~~~~~~~~>
#include <stdint.h>

typedef unsigned int apples;

apples average (uintptr_t apples_1,
                apples    apples_2)
{
  return (apples_1 + apples_2) / 2U;
}

int main (void)
{
  apples a1 = 5;
  apples a2 = 8;

  return (int) average ((uintptr_t) & a1, a2);
}
<~~~~~~~

The developer's intention is declared, and there is no undefined
behaviour, but still the uintptr_t object is mishandled, and this leads
to unspecified and unintended behaviour.

This is to show that by relaxing Rule 11.6 with 1), besides pointer
hashing and other appropriate and safe use cases, certain defects
related to how the machine-level nature of the information is handled
would also filter through. Equivalent examples applicable to 2) and 3)
can also be constructed.

I am not suggesting that there should not be a relaxed version of Rule
11.6, I am just highlighting that the relaxed version should be seen as
alternative, rather than substitutive, of Rule 11.6 - unless we are
satisfied that for the higher levels of criticality that software may
need to be developed to, the risk of additional defects skipping
through the relaxed approach is negligible.

Fulvio





More information about the C-safe-secure-studygroup mailing list