8

What is the difference between "safe" and "unsafe" code in C/C++?

I've read that "C++ is unsafe in ways which cause serious security vulnerabilities" in the article: How Rust Compares to Other Languages and More . What is insecure about unsafe code?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Eric Andrew Lewis
  • 1,256
  • 2
  • 13
  • 22
  • 14
    C++ is not unsafe; unsafe code is unsafe, irrespective of the language it was written in. – P.P Aug 09 '15 at 00:16
  • 4
    There are languages that are "inherently safe" and do not (in theory) allow the integrity of the (properly designed and configured) system to be threatened. C/C++ is not one of those. – Hot Licks Aug 09 '15 at 00:18
  • @HotLicks: Safety of a system should actually not depend in which language the programs have been written. So, what do you mean by "system"? A program? – too honest for this site Aug 09 '15 at 00:22
  • 6
    C++ has to be compiled for a specific platofrm to make that platform insecure. Other languages, eg. Java, allow cross-platform insecurity. – Martin James Aug 09 '15 at 00:26
  • 3
    IMO this is a legitimate question, it just got killed for "political" reasons (people in the C++ tag don't like to hear that their language is "unsafe"). Voting to reopen. – Matteo Italia Aug 09 '15 at 00:37
  • 2
    @MatteoItalia No it's insanely broad. First, one has to define what is and is not unsafe in C++, and that is too broad and almost certainly a flame war in the making. As for what is insecure about unsafe code, the better question is "What isn't insecure about unsafe code?" To the OP, What is unsafe varies from programmer to programmer, but for standards, look into MISRA and IEC 61508. – user4581301 Aug 09 '15 at 01:38
  • @user4581301 I would probably say almost all unsafe code comes under the category of [undefined behavior](http://stackoverflow.com/questions/tagged/undefined-behavior) that tag has more than enough material to keep someone busy for a long time. – Shafik Yaghmour Aug 09 '15 at 01:48
  • 4
    I don't believe the question was purposely meant to be inflammatory which seems to be how some have taken it but the article referenced brings up an often heard criticism of C and C++ and it is valid to try and understand it. Plenty of people are going to read that article and have the same question. – Shafik Yaghmour Aug 09 '15 at 02:38
  • The main point is that with C and C++ one can (attempt to) address or branch to locations that are not properly within the domain of the program. If there is sufficient hardware protection (properly used), interference with the rest of the system can be prevented. But with, say, Java a system does not need hardware protection (or an interpreter-based equivalent) to prevent access to resources not belonging to the current program. – Hot Licks Aug 09 '15 at 03:06
  • C++ is the perfect language for the programmer that wants to shoot himself in the foot... and in the head... and in the knee... and shoot also the people around him while doing that. Once you give somebody full access to pointers, there is nothing to stop the massacre. One day the C/++ will finally die and the world will have safe software. – Gabriel May 08 '20 at 10:19

1 Answers1

11

I believe John Regehr's article A Guide to Undefined Behavior in C and C++, Part 1 gives a good overview of what the article is getting at:

Programming languages typically make a distinction between normal program actions and erroneous actions. For Turing-complete languages we cannot reliably decide offline whether a program has the potential to execute an error; we have to just run it and see.

In a safe programming language, errors are trapped as they happen. Java, for example, is largely safe via its exception system. In an unsafe programming language, errors are not trapped. Rather, after executing an erroneous operation the program keeps going, but in a silently faulty way that may have observable consequences later on. Luca Cardelli’s article on type systems has a nice clear introduction to these issues. C and C++ are unsafe in a strong sense: executing an erroneous operation causes the entire program to be meaningless, as opposed to just the erroneous operation having an unpredictable result. In these languages erroneous operations are said to have undefined behavior.

So once we go into the realm of undefined behavior we now have "unsafe" code. Another good article that covers undefined behavior as unsafe code is What Every C Programmer Should Know About Undefined Behavior #2/3:

In Part 1 of our series, we discussed what undefined behavior is, and how it allows C and C++ compilers to produce higher performance applications than "safe" languages. This post talks about how "unsafe" C really is, explaining some of the highly surprising effects that undefined behavior can cause. In Part #3, we talk about what friendly compilers can do to mitigate some of the surprise, even if they aren't required to.

I like to call this "Why undefined behavior is often a scary and terrible thing for C programmers". :-)

The C and C++ are specified by their respective standards and we can find links to the latest ones here and those standard leave a lot of the behavior specified as undefined behavior. Which basically means the behavior is unpredictable. The C++ standard defined undefined behavior as follows:

behavior for which this International Standard imposes no requirements [ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. —end note ]

The compiler is not required to provide a diagnostic for undefined behavior and we can find many cases where undefined behavior has lead to security vulnerabilities, one of the more well known cases is probably Linux kernel null pointer check removal:

The idea is to look for code that becomes dead when a C/C++ compiler is smart about exploiting undefined behavior. The classic example of this class of error was found in the Linux kernel several years ago. The code was basically:

struct foo *s = ...;
int x = s->f;
if (!s) return ERROR;
... use s ...

The problem is that the dereference of s in line 2 permits a compiler to infer that s is not null (if the pointer is null then the function is undefined; the compiler can simply ignore this case). Thus, the null check in line 3 gets silently optimized away and now the kernel contains an exploitable bug if an attacker can find a way to invoke this code with a null pointer

Most of the time avoiding undefined behavior is a matter of good coding practice:

and using the right tools such as ubsan but there can be some obscure cases such as infinite loops that many developers may find surprising.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 3
    that "etc" is a replacemnt for a looooooooooooooooooooooooooooooo ooooooo oooo oong list of other nasty atrocious things that you need to be careful when you program in C/++. – Gabriel May 08 '20 at 10:20