Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm not sure I understand why one particular language would lend itself to more vulnerability than another. The less skilled someone is at a particular language, the more bugs/vulnerabilities he is likely to produce. It is a function of technical skill rather than a quality of the language.

For example a Ruby interpreter or a Java runtime that you trust to handle all your HTTP requests are prominently written in C/C++.

I think what makes popular packages like Ruby/Java/Rails (etc.) more secure is the sheer number of users they have. Those technologies have been hammered out over several projects and by a plethora of users and developers. Writing a component that rivals that number of interactions is tough, but certainly doable.



There's one (mainstream) C Ruby that needs to be audited. But every C CGI program needs to be audited.

C programs are susceptible to memory corruption. Programs written in practically every mainstream high level language are not susceptible to those problems (until they start using third-party C extensions). That's the security win of not using C code.


"I'm not sure I understand why one particular language would lend itself to more vulnerability than another."

http://en.wikipedia.org/wiki/Buffer_overflow

From that page: "Programming languages commonly associated with buffer overflows include C and C++, which provide no built-in protection against accessing or overwriting data in any part of memory and do not automatically check that data written to an array (the built-in buffer type) is within the boundaries of that array."


I would call that a programmer error. The language certainly does make it harder to write "safe" code, but it is certainly doable.

I guess my point is that the tools/libraries/frameworks on top of the language are what make it useful or not useful, independent of the language itself. For example, writing a web app in Ruby may not help you against SQL injection (http://en.wikipedia.org/wiki/SQL_injection) unless you have a well designed query language on top of that.


Everyone calls it programmer error. But when you make the same error of copying arbitrary-sized inputs from attackers into a Java program, you do not enable that attacker to upload their own code into the JVM process and run it.


But doesn't the use of Java's JNI invalidate any security the JVM offers? As far as I know, any protections the JVM puts up are invalidated once you inject native code, which would potentially enable an attacker to potentially inject malicious code that hijacks the JVM. Then again, one could argue that the JNI is no longer a "Java" program.


Yes, when you write C code and attach it to JVM processes, that puts the JVM process at risk. More C code, more problems.


"""I would call that a programmer error. The language certainly does make it harder to write "safe" code, but it is certainly doable."""

Everything is "certainly doable" in a turing-complete way, but that fact has not mattered at all in the evolution of programming languages.

It doesn't matter if it's "certainly doable", what matters is how easy it is.


Things like memory protection by default do make some languages safer than others.


Yes, however, there are libraries in place that can circumvent some of these issues: e.g., boost::shared_ptr in C++.


No, Boost shared_ptr exacerbates the issue by creating a second regime of reference counting that, if contravened anywhere in the program (for instance, in any third-party piece of library code, which every C++ program of any real size is replete with) creates use-after-free conditions.

I invite you to continue coming up with examples of ways to reliably mitigate memory corruption flaws in C/C++ programs, because I enjoy this topic very much, but as your attorney in this matter I have to advise you that you're going to lose the argument. :)


After doing some research on the topic, I will have to say that I concede my point. ;-)


I agree with you on the gist of your argument (I think), but there are 'ways to reliably mitigate memory corruption flaws in C/C++ programs'. For example, using std::string rather than malloc()'ing a char* every time you do something that works with strings is certainly a way to reliably mitigate memory corruption flaws in C++.


True as far as it goes; std::string is safer than libc strings. If all your program does is manipulate strings, and not marshaled binary data structures or protocols, and your data structures are simple and you're very careful with your iterators (which themselves often decompose to pointers) and your object lifecycles are simple enough that you can reliably free things and know you're not going to accidentally touch the memory later, and-and-and, you can write a safe C++ program.


Every boost::shared_ptr I see is a cringe-inducing experience. It's not just the atomic memory operation that happens whenever you copy it, it's the programmer who thought that he could just put things in a boost::shared_ptr and it would solve his problems. Now the code is less readable, because you don't know what the lifetime of your resources are! The worst thing is when they get shared across threads, and suddenly you don't know what thread your object's going to be destructed on.

One better alternative to a shared_ptr is a noncopyable shared pointer type. You have to explicitly copy it with a call like

    x.copy_from(y);
That this makes the use of reference counted objects more verbose and uncomfortable is not a downside.

Really this should be a noncopyable version of intrusive_ptr, not shared_ptr. Either the object is owned by references on multiple threads and you'll want to be careful about what thread you destroy it from, and perhaps then you'd want to send a release message over some message queue system, or it's a single threaded object and you don't need the overhead of atomic memory operations.


> Now the code is less readable, because you don't know what the lifetime of your resources are!

You're certainly making a valid point; however, as far as how important this is, the experience of a lot of people out there points in the other direction.

Consider: the lifetime of a Python object is essentially the same as that of a C++ dynamic object owned by a shared_ptr. But you don't see Python programmers complaining that they can't figure out when their objects are going away. In Java it's even worse; an object's lifetime is pretty much whatever the JVM thinks it ought to be. I have seen complaints about this, but not many, and the JVM's reputation as a platform for serious languages remains pretty strong.

On the other hand, memory leaks in C (and C++) programs have been a major thorn in all our sides for decades.

So, yes, when you get assured destruction by using an object whose lifetime is managed for you, you do lose something. But the experience of programmers all over strongly suggests to me that, for most applications, what you get, is much more valuable than what you lose.


At the risk of sounding like flamebait, it's because Python and Java developers don't know what they are missing without deterministic destructing. Of course there are way to 'code around' it, but knowing the exact lifetime of objects is very often very useful, and often makes for much easier to understand code and easy ways to avoid resource leaks.


try..finally blocks have 80% (or more?) of the advantages of deterministic destructing without the costs, especially for avoiding resource leaks.


What about objects who are referenced by more than one object, and which are linked to resources? try... finally blocks are just a different way of freeing your resources at the end of a block, and won't help with objects which outlive the block they are guarding.

Actually, here is your choice: either you'll have to manage every kind of resource except memory (garbage collected languages), or you'll have to manage only memory (C++).


Yes, that's true, but at the cost of syntactic noise. It's a preference, and one gets used to it I guess, but to me all the try blocks are harder to read than code where variables have a fixed lifetime, so where you in many cases can avoid the extra indent level.


> You're certainly making a valid point; however, as far as how important this is, the experience of a lot of people out there points in the other direction.

That's because I'm talking about C++ and you've somehow decided to talk about something unrelated. Python and Java programmers still care about all resources that aren't object lifetimes.


After doing some thorough research on the topic, I would like to say that I concede my point about the vulnerabilities of C/C++. Thanks tptacek.


Happy to help! :)




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: