This is not about Fortran, but noteworthy given that one branch of government embraces migrating all codebases to C++ while the headquarters is urging developers to migrate away from it.
I believe Fortran is not strictly memory-safe either, but for the kinds of scientific computing where Fortran is a realistic alternative to C and C++, are Fortran programs less likely to have “buffer overflows and other memory access vulnerabilities”? Here is a link to the technical report.
I think the bigger difference between Fortran and C wrt memory safety is use case. Memory safety is primarily an issue in code that receives inputs from untrusted users (e.g. web servers, OSes, image decoders etc). Fortran would likely be about as bad as C for these use cases (possibly worse since the strict aliasing rules are a whole new class of UB that C doesn’t usually have), but for programs that are primarily run by trusted users, memory safety is a lot less of a problem.
Fortran would have been on this list if it was more popular or used for newly started projects like C++ is.
Let’s not kid ourselves, yes you could put everything in modules and compile with all the checking and debug flags in the world. No, Fortran was never designed to be a “safe” language in the same way that Rust was from the beginning.
The other languages the article considers are all garbage collected I believe.
We can talk about Rust being “safe by design” when the Rust community agrees on a formal specification for the language that compilers must obey to be considered conforming. I think this point is missing in a lot of discussions. There is no reason why concepts and principles from Ada (used in safety critical systems) can’t be adapted to C. In some cases, they have been (ie. the CompCert compiler).
Stroustrup was interviewed 11 months ago about this – the advice to dump C and C++ is not coming only from the U.S. government. He disagrees , and his proposals to improve the safety of C++ are in Safety Profiles: Type-and-resource Safe programming in ISO Standard C++. The approach
is “a cocktail of techniques” not a single neat miracle cure
• Static analysis
to verify that no unsafe code is executed.• Coding rules
to simplify the code to make industrial-scale static analysis feasible.• Libraries
to make such simplified code reasonably easy to write
to guarantee run-time checks where needed.
I agree that Fortran is vunerable to memory based problems but I’ve found that as your post suggests that a lot of them (but sadly not all of them) can be eliminated or reduced by adopting sensible coding standards and practices.
Mainly,
-
Avoid the use of pointers at all cost (or at least reduce their use to only the cases where its almost impossible to implement an algorithm without them)
-
Turn on bounds checking during code development and debug and go the extra step in checking bounds and array sizes at some point during each execution of a given problem.
-
Write code that minimizes (and traps) overflows and underflows.
Unfortunately, defensive programming can take a lot more time and money than ignoring the potential for memory “crimes” so most folks don’t bother.
Rust is safe in Release mode also, but the price for it is that it leaves array bounds checking on at all times, which I think must slow some things down, such as CSR arrays when the compiler can’t prove inbounds access at all times.
Fortran workarounds this problem by having Debug and Release compilation modes and in Debug mode indeed it is 100% safe if you don’t use pointers, only allocatable arrays. And even pointers I think could probably be checked by the compiler, although most compilers don’t.
C++ can also be used safely, although compilers help even less there.
I did not know that release mode rust checks array bounds. That seems pretty bad for performance usually.
Also I guess it’s just a fundamental disagreement but compiler flags are not an acceptable answer to say “this code is safe” in my mind. Different compilers have different defaults, different options, and all of them are subject to change.
I don’t think Fortran necessarily needs to be safe either. It doesn’t act as a system language anymore so there usually isn’t a lot of OS interaction that a Fortran program does besides read and write text (maybe binary) files to disk.
I’d rather say, avoid allocating pointers. Using pointers to point to already allocated memory is fine (at least if we speak about memory leaks)
Wikipedia says:
“Memory safety is the state of being protected from various software bugs and security vulnerabilities when dealing with memory access, such as buffer overflows and dangling pointers. For example, Java is said to be memory-safe because its runtime error detection checks array bounds and pointer dereferences. In contrast, C and C++ allow arbitrary pointer arithmetic with pointers implemented as direct memory addresses with no provision for bounds checking,[2] and thus are potentially memory-unsafe.”
So… Java is memory safe because of run-time error detection. On that basis it’s a quality of implementation issue - and I can think of current Fortran compilers which are memory safe. If the Fortran standard mandated those run-time checks, it could be called a memory-safe language. The same may possibly be true of C and C++, but that’s beyond my ken.
I would like to add another condition for a truly memory-safe language. I think it should disallow any use of data in storage locations which were not explicitly assigned a value by the program’s own code. Data could be defined or assigned in the code, or read from an external source, or computed by the program. Again, there are existing Fortran compilers and tools which perform those run-time checks (and they do have to be run-time checks!)
Which ones, may I ask? I guess one would be NAG. One could advocate for Fortran by pointing to a memory-safe implementation of it.
Yes but then you are just restricting pointers to be aliases for all or part of another entity. In other words giving it another name which I thought was what the ASSOCIATE construct was for. Speaking just for myself, I would have actually preferred the ability to give a pointer an explicit alias attribute that signals the compiler that you are just trying to associate a new (shorter probably) name to another entity and are not going to allow it to point to a (previously) unnamed block of memory and/or once associated change that association to a new variable. I would also restrict them to be just local to a given scoping unit (ie inside a subroutine or function}. Yes I know this would be redundant with ASSOCIATE but I’ve found ASSOCIATE to be very clumsy to use for anything beyond a couple of variables. I just think something like
Real, pointer, alias :: a(:)
or just
Real, alias :: a(:)
Real :: this_is_a_very_very_long_name(:)
a=>this_is_a very_very_long_name
would for me be better when you have a lot of long names for type components etc. or you want to keep existing names in an old code you are refactoring than relying on ASSOCIATE which I believe still is buggy in some compilers.
Just my 2 cents
UB is also a memory safety issue. to be memory safety, fortran would have to add explicit checks, prove, or stop optimizing based on the lack of aliasing it currently assumes.
ASSOCIATE
doesn’t fulfill all the needs. Pointers can be used to restructure some existing data into derived types without duplicating them.
The other one is Silverfrost (formerly Salford) Fortran, which despite its limited language support, and occasional idiosyncrasies is a compiler that I personally swear by (and at!).
I used to maintain charts showing how well different compilers dealt with programming errors - mostly of the type described here as memory safety errors. The chart is stll online, but I no longer maintain it. As you can see Silverfrost FTN95 and NAG lead the field. I understand that from version 8.60, Silverfrost now checks illegal aliasing in subprogram arguments, and claims 100% pass rate.
See my reply to Beliavsky - just posted. The Silverfrost compiler does check for illegal aliasing in subprogram arguments.
Thanks. When was the chart last updated? I may tweet about it. Lahey-LF95 is ranked 3rd among compilers, and I was a happy customer for many years. Does nvfortran support many of the same compiler options as PGI?
It was October 2015. The version numbers were Absoft 15, FTN95 7.20, Intel 16.0, Lahey 7.30, NAG 6.0 and PGI 15.7. I have no idea what changes Nvidia have made to the PGI compiler since then.