Java is not a safe language

The prime directive in programming is to write correct code. Some programming languages make it easy to achieve this objective. We can qualify these languages as ‘safe’.

If you write in C++ without good tools, you are definitively in the ‘unsafe’ camp. The people working on the Rust programming language are trying to build a ‘safe language’.

Where does Java lie?

Back when Java was still emerging, I had been tasked with building a new image compression library. I designed a dual Java/C++ library. My client was a company providing medical services, but they had no use for the Java code. To this day, I think that they only use the C++ code.

When I tried to sell them a license to the Java code, I stressed that Java was safer, had automatic memory management and the like. Their top engineer looked at my Java code and spotted a potential memory leak. Yes, Java has memory leaks. You may have been told that it does not happen, but it happens all the time in real systems. We had a beer and a good laugh about it. Meanwhile, he had been able to prove that my C++ code was safe and did not have memory leaks.

In any case, most people would agree that Java is ‘safer’ than C++, but as my story illustrates, it is more of a statistical statement than a black-and-white one.

Is Java a safe language in 2019?

It is a time-dependent culturally-loaded question, but I do not think of Java as a safe language today. If ‘safety’ is your primary concern, then you have better options.

Let me review some examples:

  1. Java does not trap overflows. That is, if you are trying to count how many human beings there are on Earth using a Java ‘int’, incrementing the counter by one each time, the counter will overflow silently and give you a nonsensical result. Languages like Rust and Swift catch overflow. The Java standard library has some functions to guard against overflows, but they are not part of the language. As a related issue, Java promotes and convert types silently and implicitly. Can you guess what the following code will print out?
    short x = Short.MAX_VALUE;
    short y = 2;
    System.out.println(x+y);
    int ix = Integer.MAX_VALUE;
    int iy = 2;
    System.out.println(ix+iy);
    

    This type of behaviour leads to hard-to-catch bugs.

  2. Java allows data races, that is, it is possible in Java to have several threads accessing the same object in memory at the same ‘time’ with one thread writing to the memory location. Languages like Rust do not allow data races. Almost anyone who has programmed non-trivial Java programs has caused or had to debug a data race. It is a real problem.
  3. Java lacks null safety. When a function receives an object, this object might be null. That is, if you see ‘String s’ in your code, you often have no way of knowing whether ‘s’ contains an actually String unless you check at runtime. Can you guess whether programmers always check? They do not, of course, In practice, mission-critical software does crash without warning due to null values. We have two decades of examples. In Swift or Kotlin, you have safe calls or optionals as part of the language. Starting with Java 8, you have Optional objects in the standard library, but they are an afterthought.
  4. Java lacks named arguments. Given a function that takes two integer values, you have to write ‘f(1,2)’. But is it instead ‘f(2,1)’? How do you know that you got the parameters in the right order? Getting confused in the argument order is a cause of hard-to-debug problems. Many modern programming languages have named arguments.

Ultimately, I believe that while some programming languages make it easier to produce correct code than others, much of it comes down to good engineering practices. I would never go as far as saying that programming languages do not matter, but I bet that ‘who’ writes the software is a lot more important.

Published by

Daniel Lemire

A computer science professor at the University of Quebec (TELUQ).

36 thoughts on “Java is not a safe language”

  1. I was hoping you would give some more examples of languages that are very safe, after having pointed out languages that are not. For me, Haskell comes to mind, and you did mention Rust, but what other modern languages are there that have learned from history and avoid these pitfalls that many “safe” languages still have?

    1. I wouldn’t call it modern, (and that’s a good thing in my books), but Ada certainly has a ton of safety features that Java lacks.

      1. Ada is not allowed to have subsets or supper set which is a VERY good thing. There is a subset language SPARK which is very safe. I think it beats Rust.

        I do not understand the Modern Language issue. Ada 2012 is a modern language. The language standard is available for free and a very readable document. There are some excellent compilers including a gcc based one.

  2. And here I thought this was going to talk about array variancy or null-related soundness bugs in generics (not a major problem because it is papered over by generics erasure and compiler inserted casting checks.)

    The key benefit of Java’s safety is that correctness bugs do not cause spooky action at a distance.

    A broken linked list implementation on the JVM will not cause your password checking code to break.

    This is fundamentally different to C++ where a broken linked list implementation can lead to arbitrary memory corruption, overwriting the return pointer and then jumping past the password checking code.

    I do agree that memory leaks are a problem. IMO a proper VM for the future should support isolated heaps sort of like Erlang or the Midori project.

    Do note that data races on the JVM are specifically limited (and consequently lead to slower code) in a few ways such as that final fields have a storestore fence after them and object references and values other than doubles and longs do not tear and so careful enforcement of Java’s sandboxing is theoretically possible (although often flawed in practise.)

  3. Starting with Java 8, you have Optional objects in the standard library, but they are an afterthought.

    Optional can also be null.

  4. Java is also not safe with variance in generics.
    Kotlin is a good example of a language that improves on language safety with generics and null. It doesn’t have nulls (although it’s untagged union None type happens to be named “null”)

  5. None of these issues are the things that spring to mind when language “safety” is mentioned. I think of language safety as exclusively the issue of memory safety. Java is memory safe. You won’t get buffer overrun exploits like you can with C/C++.
    A null pointer exception or an overflow is annoying but it’s unlikely to lead to someone hacking your computer.
    TL;DR I don’t think your definition of language “safety” matches what most people mean by the word.

      1. Java is so far behind some of the other languages on the market today it’s not even valid to consider it safe anymore. About the only place where it’s safe is buffer overruns, but as the author pointed out simple scaler operations can result in uncaught overflows. Dartmouth BASIC was safer.

        1. A scalar overflow is not going to give a hacker access to your computer. There’s a difference between actual safety of your computer and nice to have language features

            1. Despite the name this still seems more like a result of the direct access to the memory (which you dont have in java) rather than the integer overflow.

              And sure if you really try hard, any language idiosyncrasy when overlooked, can cause a bug, and any bug can potentially be a security risk if you keep trying really hard.

              But this article doesn’t make a single valid point from the first to the last word. Utter nonsense

              1. So Nikolay, is it fair to say that you think that the engineers who design languages that, for example, trap overflows in the name of safety, are misguided?

                Would you say that a programming language that prevents data races is not safer?

                Would you say that preventing data races is not a safety feature… It is a waste of engineering time on the part of language designers?

                1. Preventing data races is a great feature. Its part of what’s great about Rust. But if not preventing data races is ‘unsafe’ then all the languages on the top of the Tiobe index are unsafe.
                  Again, not saying that these are not good features to have – totally agree that they are – but when you say a language is unsafe I believe that means memory-safety to most people.

                  1. I did not state that Java was unsafe without qualification. Safety is necessarily a relative statement (that’s explicit in my post). Here is my specific claim:

                    If ‘safety’ is your primary concern, then you have better options.

                    Do you disagree with this statement?

                    If you disagree, then you have to believe that you do not have better options. Why not?

                    all the languages on the top of the Tiobe index are unsafe

                    Python is up there in the top 3 right now. It has decent safety features. I certainly consider it safer than Java.

                    1. Then consider changing the title of the article to “If ‘safety’ is your primary concern, then you have better options (than quite a bunch of languages)”. And not the bombastic click bait that it is now. And please don’t start with a C++ vs Java anecdote, C++ probably is on the top of the “unsafe languages” list, by a margin.

                      I am not saying anyone doing thing differently than java is misguided or waste of whatever. I might actually even agree that trapping overflow is a good idea. But not in the name of safety, because, it has hardly anything to do with safety.

                      You keep throwing the word “safety feature”, “in the name of safety” etc. before any feature, but, again i told you you can do that with any language idiosyncrasy. Let me illustrate:
                      – Duck typing in Ruby is not safe, because people who don’t know what duck typing is can make mistakes or not read the code properly and that mistake might hypothetically sometimes have something do with security.
                      – in JavaScript, 1 == “1” is true and safety safety safety safety…

                      I mean you are a genius. Each week you can come up with an article like this and even use the same 4 reasons and just plug different language every time. Then eventually maybe come up with a new unrelated to safety reason for the sake of variety and write about some other languages that lack that feature.

                    2. So catching overflows is unrelated to safety, that is, it does not help to prevent bugs and programming errors… is that what you think? Why is it being introduced in other programming languages?

                      C++ is indeed less safe than Java in most (but not all) ways. However, my point should be quite clear I would hope: Java is safer than C++ but not nearly as safe as a language can be.

              1. The C#, Swift, Rust (etc.) people trap overflows in the name of safety. Java does not trap overflows. (That’s just one example from my list which is meant as a list of examples.)

                Either you agree with people who think that trapping overflows is a safety feature, in which case you must conclude that Java lacks at least this one safety feature… Or else you disagree that it is a safety feature and you think that these other language designers are misguided.

                The same issue goes for data races. Some languages prevent data races, Java does not. If you agree that preventing data races makes the programming language safer, then you must agree that Java lacks this safety feature and is thus less safe than it should be. Or else you think that preventing data races is not a safety feature.

                And so forth.

                If you think that unchecked overflows are safe, then I want to hear you argument. On the other hand, nobody cares whether I am right or wrong.

                Please offer your insights.

      2. Oh, absolutely not. I really like a lot of the ideas in Rust – like borrow checking – for example. But a lot of the things being listed as unsafe are a little silly – named parameters for example. It’s syntactic sugar and its something that most IDEs make redundant (by displaying the parameter names as you write or introspect the code).
        Don’t get me wrong, I think all the features in the article are nice things to have, but if we restricted ourselves to languages that implemented all these, we’d exclude pretty much everything on the top of the Tiobe index which is not really a practical or helpful position to take.

        1. It’s syntactic sugar and its something that most IDEs make redundant (by displaying the parameter names as you write or introspect the code).

          The problem is not that the user can’t tell which parameter is which… the problem is that someone casually reviewing the code will not spot the problem.

  6. The 4th point is not an issue. If you use an advanced IDE like IntelliJ IDEA from JetBrains, it will show you argument hints. Also, instead of having a method which takes two arguments, you can have a method which takes a single object with clearly named properties.

    1. If you use an advanced IDE like IntelliJ IDEA from JetBrains, it will show you argument hints.

      All the time when you browse the code, or just when the intern coded it in two years ago?

  7. Ada can handle 1 and 4 and has been able to since Ada83.

    Modular types will wrap around, other types will raise an exception.
    Ada allows data races, but you can control that by wrapping inside a protected object when using tasks.
    Ada added “not null” access types (pointers) to handle this, but it’s an afterthought and they’re not “not null” by default.
    You can use named parameters and you can write them in any order you like, as long as they are named.

  8. No general purpose language is safe, or should be safe given the statements in the blog.

    Preventing a memory leak as described would prevent the user to allocate memory when needed. Even if C++ still offers the faster memory allocation, allocating/de-allocating memory is not realtime safe (as it can generate an unexpected delay) and shall be avoided.

    My two cents on the issue:
    – programming languages are generally safe, the problem is that people are not safe.
    – people safety can be achieved by better management flows (like implementing CMMI), by educating people and/or by adding redundancy in the development (expensive).
    – there are always syntax candies (named parameters is one) the mainstream languages are missing. Still, I can write a perfectly Object Oriented and structured code in COBOL if needed. If you want to write good code, the key is the mindset, not the language.

  9. There are also issues surrounding fuzzing the JVM that further supports arguments against Java safety. Had initially looked forward to developing software in Java, returning to it after many years, only to find that security as well as real world memory issues plague the language. Quite a bit of wasted time and energy -sad, but had to cut off the romance.

  10. The security with which an application is programmed using any language is relative and depends on the experience of the programmer.

  11. Safe in what manner? Any competent programmer will understand variable volatility and overflows. What are actual unsafe practices such as heap/stack overflows into code and the possibility of executing malicious code injected via buffer overflow(s)?

  12. Regarding the safety issues here discussed, how safer/unsafer is C# compared to Java? If I recall correctly, C# has the checked/unchecked statements to prevent arithmetic overflow. Although C# explicitly lets you include unsafe code like pointer arithmetic. C# has memory leaks as well, no doubt, and while it has syntactic sugar to allow disposing objects in a deterministic way, it does not enforce it. C# has named arguments, and C# 8 will add nullable reference types, meaning any object will have to have a valid reference and cannot be assigned null unless specifically indicated by the programmer. On the other hand, C# has dynamic objects, which throws type-safety away.

    Any thoughts?

    1. My own impression is that C# is generally safer, more modern than Java, for many of the reasons you invoke and others as well. C# makes it easier to get multithreading right, for example.

    2. C#’s dynamic objects does not mean that C# is unsafe in general. It means it provides a specific, explicit, escape hatch for when you need to do something not feasible within the type system. For the same reason, Rust’s ‘unsafe’ feature does not mean that Rust is unsafe, it just means there’s an escape hatch if you need it.

Leave a Reply to Jorge sainz Cancel reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax