8 ms·
The point I'm about to make in this comment is so old and has been said so many times that we all are tired of hearing it. But why do we use a language like C++
by yjgyhj 10y ago
The point I'm about to make in this comment is so old and has been said so many times that we all are tired of hearing it. But why do we use a language like C++ to implement something where we don't wish to have bugs?
C++ is not memory-safe (no GC or whatever Rust does), it's not type safe (in the ML sense), it relies on writing to memory a lot (instead of having pure functions). Had this program been written in Ocaml or Haskell or a strongly typed functional Lisp, this bug would have been impossible to make.
Why do we do this, still? Is it not irresponsible?
- willtim 10y agoLuckily there are some Blockchain/Crypto currency startups that do understand the value of using something like Haskell. See https://iohk.io/projects/cardano/ https://iohk.io/projects/cardano/
- wyager 10y agoThese pump-and-dump schemes are getting ridiculous. Implementing a cryptocurrency client in Haskell isn't enough to justify creating an entirely new currency. Whether or not the protocol itself is sound is (almost) completely orthogonal to the language in which it's implemented, and at this point there are dozens of Bitcoin clients written in many languages (including Haskell [1]), so it's extremely unlikely that Bitcoin as a whole is still at risk from unsafe language choice. 1: http://haskoin.com http://haskoin.com
- NKCSS 10y agoBecause old habits die hard. Using 'unmanaged' languages for 'performance' reasons is no longer a good reason, because the likes of C# have shown multiple times that there is no reason to choose C++ over C# if you look at performance alone (difference is neglible).
- iopq 10y agoThe difference is not negligible: http://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=csharpcore&lang2=gpp http://benchmarksgame.alioth.debian.org/u64q/compare.php?lan... Sure, it's silly benchmarks, so I wouldn't take the results as gospel. But the fact is, nobody who writes C# managed to produce a benchmark yet that beats a C++ program. Fast languages like Rust have managed to at least match the performance of C in some benchmarks (and even beat it in others).
- hvidgaard 10y agoProperly unmanaged code will probably always be faster than managed code. But the point still stands. Code in a managed language, identify the hot spots and inject highly performant unmanaged code there. There is no need to go full C++ for 99.999% of all projects.
- igouy 10y agoLike this? http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&lang=csharpcore&id=5#log http://benchmarksgame.alioth.debian.org/u64q/program.php?tes... How should /unsafe be set with .Net CORE csproj ?
- igouy 10y agoI only knew the command line option which no longer worked. Once I found the project.json "buildOptions": { "allowUnsafe": true } I was able to fake something for dotnet migrate and find the needed setting: <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup> </Project>
- willtim 10y agoIt's worth pointing out that the majority of large C++ projects contain non-deterministic memory management (reference counting) and cache-inefficient object structures like C#.
- iopq 10y agoAbsolutely. But note that if you don't have cycles, reference counting of SOME objects is faster than having a GC for everything. The RAII idiom when used in C++ helps with statically determining that some objects can be released at defined points without having to reference count them.
- NKCSS 10y agoIf they were properly written, I'd accept that, but just take a look at how vastly different things these two are doing: http://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexdna&lang=gpp&id=2 http://benchmarksgame.alioth.debian.org/u64q/program.php?tes... http://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexdna&lang=csharpcore&id=8 http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...
- oselhn 10y agoWhat is even worse that those guys are not able to use C++ properly. They created function with more than 1000 lines with so many branches! It will be almost impossible to write test which tries all code paths. I do not think that changing language would help in this case with such programmers. The bug happened in "inlined constructor" so they should check all uses of this class/struct to check if it is not copied to other places (and probably all other structs/classes).
- mulmen 10y agoDepends on your definition of irresponsible. Companies exist to make money so the most responsible thing to do is make as much money as possible. If breaking the law means you will make more money then do it. See: a x b x c = x formula from Fight Club or Uber's entire business model. Your assumption that we don't want bugs is probably why you are asking the question. Companies don't care about bugs, they care about losing money so if the bug doesn't cost money it's not worth fixing until it costs more than the fix. I think this is actually very short sighted but that's just how the incentives align in our current system. I make no claim to the philosophical implications of any of this.
- robertgraham 10y agoIt's an absurd point. ZCash was built upon the Bitcoin codebase. This inherits a lot of bad decisions. Moral purity, demanding they start over again from scratch, just isn't practical. The bug in question could have been solved had the simply compiled with minimal static analysis -- by which I mean -Wall. C/C++ is memory safe if you turn on dynamic checking. Sure, it's twice as slow as C/C++, but still tons faster than nonsense languages like Ocaml or Haskell.
- im3w1l 10y ago> C/C++ is memory safe if you turn on dynamic checking. Is anyone here doing this? Would be interesting to hear your experience.
- jhasse 10y agoIf valgrind counts, then yes.
- kzrdude 10y agoNo, there is no dynamic checking that guards against iterator invalidation in general. You can't make it memory safe with gcc or clang.
- aij 10y ago> C/C++ is memory safe if you turn on dynamic checking. What's the option to turn that on? Which compilers is it in? I know there were several fat-pointer patches to GCC back in the day, but I didn't think anything remotely similar had ever gone mainstream. There's just too much existing code that relies on undefined behavior last I checked.
- Sanddancer 10y agoBecause pretty much any language that's been touted as a replacement has problems which need solved before they'd really be viable. They're either single vendor with no independent standardization, like Rust or D, or have lower performance like go, or both. Once both problems are fixed, it'll be a lot easier to start looking at alternatives. Until then, there's not a language that settles into a lot of the niches C and C++ operate in. This case specifically, a lot of the issues that allowed this to happen were logic errors which would have been valid in most languages. A functional language would not have helped very much here. C and C++ are still used because they work, and have huge ecosystems around them. There's a lot of tooling around them, the compilers build fast, code, and are available for pretty much every planet under the sun. This particular case, it would have helped a lot if the developers looked at the warnings of the questionable code they had made, but they seem to be of the "it compiles, ship it" type that would have let those things fly regardless of the language.
- adrianN 10y agoAda has multiple implementations, is pretty safe, and produces fast code. Yet it isn't popular, so I guess there are other factors that are more important than number of compilers and speed.
- beaconstudios 10y agolanguages suffer from the same network effect as social networks. You could argue that Ada is a better programming language or that Ithkuil is a better spoken language but unless other people are also using them, you'll struggle to get help or hire people (or get contributors).
- gmfawcett 10y agoAda isn't my favourite language to code in. But if I was tasked to build something safety-critical, I would strongly consider Ada SPARK [1] among the possible tools to use. [1] http://www.spark-2014.org/about http://www.spark-2014.org/about
- yjgyhj 10y ago
- petters 10y agoAs far as I can tell, this bug has nothing to do with memory-safety. And I don't think C++ is to blame here. It's just a lot of untested code. Surely even Ocaml and Haskell need tests.
- yjgyhj 10y agoYes, this bug is not about memory safety - but having the state-writing operator so easy at hand was probably what lead to the mistake in the first place. In my GP comment I went on to rant about other classes of bugs which are obsolete since the 1970s, but still happen.
- willtim 10y agoNo C++ is to blame. This type of error could never happen in OCaml and Haskell.
- zuzun 10y agoYou are looking at a 1k LOC function in a 7k LOC file with a bug that can be easily spotted by -Wall and you think it's the fault of the programming language? The only thing irresponsible is putting your hard-earned money into the 100th Bitcoin fork maintained by some guy with an Anime avatar. Once you stop trusting the developers it essentially becomes an underhanded ... contest and no language wins.
- ifdefdebug 10y agoDidn't try, but I could imagine that running -Wall over that codebase produces huge amounts of noise rendering it practically useless, until somebody gets to fix all warnings which are not bugs.
- diamondo25 10y agoRunning static analyzers (PVS-Studio, for example) and splitting up functions to simple things should at least make it easier to detect errors.
- yoklov 10y agoFor splitting, there's a balance you need to strike. Split things up too far and the errors are definitely harder to detect. IMO rote splitting usually doesn't simplify, it just hides the complexity.
- akvadrako 10y agoIn any trusted codebase fixing every -Wall warning is the least you should aim for, possibly with a few intentful exceptions. Not doing so is very sloppy.
- josefx 10y ago> -Wall over that codebase produces huge amounts of noise rendering it practically useless As a c++ developer I would nope the hell out of there or spend a month fixing the warnings - depending on pay. No way would I work with something in that state long term. > until somebody gets to fix all warnings which are not bugs. Code that is filled with ignored warnings generally gets worse, not better. Having little to no quality standards does that.
- easytiger 10y agoThis bug had nothing to do with c++ and its ergonomics, let alone it's safety. > Unfortunately when populating the denomination member variable, an equality operator was used instead of assignment, resulting in the denomination always being zero, as set in the class constructor. So = Vs ==
- lmm 10y agoThat is absolutely a bug in C++'s ergonomics. Languages that use pascal-style := for assignment would not have this problem. Languages that don't have the surprising value behaviour of = would not have this problem. Hell, even as crude a language as Java would not have this problem because it doesn't allow an integer to implicitly decay to a boolean. Building with warnings on would also have caught it, but the fact that someone started a new project without this warning turned on shows that C++'s defaults around warnings are bad, which is an ecosystem ergonomics issue.
- kzrdude 10y agoYeah, let's compare with a stricter language: In Rust, x = y evaluates to (), not any of the values in x or y. In Rust, numbers are not implicitly usable as booleans in conditionals.
- lmm 10y agoIndeed, just as in every other ML-family language since 1973. (I'm glad these things are finally getting mainstream attention, but I'm not sure why people get so excited about "Rust features" that are almost all taken straight from Ocaml)
- aij 10y agoHey, I'm just glad to see 1970's PL research finally making it to the mainstream(ish), regardless of which language gets the marketing credit for it. I think the main advantage Rust has over OCaml is that it is syntactically more like C. But, hey, if it's what gets HM-style type inference to the masses, I'll take it.
- lmm 10y ago"We" don't. But yeah, using C++ is stupid, and anyone paying attention knows this by now. At this point the only thing is to point and laugh and raise the new generation better - I fear that, like science, programming practice will have to advance one funeral at a time.
- lordnacho 10y agoIt's a good point, but there's also market forces to contend with. If you make your new coin based on a functional language, there's fewer people who'll be able to jump in and code. c++ looks similar enough to the other {} languages that many people will have the skills to give it a go. Unfortunately it's different enough that you can really mess things up, but you already know that.
- nfd 10y agoI really hope amateurs with "a {} is a {} is a {} is a {}" level skills aren't working on cryptographic or financial software in C or C++. Write Rust, though, which is {}, and at least the box of hand grenades you're giving them doesn't have all the pins pre-pulled.
- riprowan 10y agoWhat language can be better peer-reviewed?
- yjgyhj 10y agoA purely functional statically typed one, like OCaml or Haskell, because there would be so much less to review, and an insane amount of the reviewing work is automatic. Zero bugs around state, zero bugs around memory mgmt, zero bugs about error conditions not being handled, zero bugs due to some data being expected but not being written, etc.
- xcthulhu 10y agoWell, a couple months back I attended a talk on a Haskell implementation of the Noise protocol. The programmer admitted that he was a cryptography novice, and in fact a Haskell novice. As a result the code he wrote is needlessly abstract - for one thing the guy uses Free monads and in turn ropes in template Haskell as part of his state model. I really have no idea what code he's generating. The code has other features that make review challenging - for instance he doesn't qualify any of his imports so it's hard to tell where to look for the functions he's implementing. Maybe you are better at auditing Haskell than I am. As DJ Bernstein writes in various places, one common exploit is to construct an elliptic curve Diffie Helman shared secret with input that isn't a curve point. I really can't tell if the guy is mitigating against this attack or not, but here you can have a look: https://github.com/centromere/cacophony https://github.com/centromere/cacophony
- _pmf_ 10y agoHN's law: all problems with C can be solved by writing a sufficiently high-brow post containing snide observations only a sophomore is smart enough to come up with..
- spacemanmatt 10y agoAu contraire. I've had a long career in the field (various domains, I'm always the "code guy") and it's actually useful to me to hear people besides myself expressing the level of surprise/frustration/bemusement they experience. It keeps the trade from being utterly dry.
- yjgyhj 10y agoFirst of all, there is no need to be mean, even if I understand you mean well. Isn't it true though, that with some techniques certain bugs are impossible to make? If you have not experienced it, I recommend you to seek it out and try.
- phkahler 10y agoThe problem isn't in the implementation, it's a problem with Zcoin itself. One should not be able to create Zcoin via software whether that's a bug or deliberate.
- gnode 10y agoHow do you propose one creates Zcoin then?
- phkahler 10y agoSorry, that wasn't clear. With bitcoin you could create it at will, but it requires doing a certain (constantly increasing) amount of computational work. Work that can be verified. There is no way for a bug to accidentally create a bunch of bitcoin, and no way for anyone to deliberately create any without doing the work.
- xcthulhu 10y ago> Why do we do this, still? Is it not irresponsible? One reason is security - if cryptography isn't done in constant time then there is the potential for timing attacks. This is why BitCoinJ ditched BouncyCastle for their own JNI wrapper around BitCoin's libsecp256k1. There is a rust client for Ethereum, called Parity - they do FFI calls to libsecp256k1. Similarly rust-crypto vendors most of its crypto in C that it calls through FFI. Similarly go-ethereum also uses libsecp256k1. However, I know that Tendermint uses Ed25519 instead of secp256k1, and in turn they use NaCl which does not involve FFI. Mining for Ethereum is done on a GPU, so the miner code is necessarily written in OpenCL or CUDA. There are a few blockchains written in functional language but they are new to the scene. There were a couple of Haskell Ethereum clients but they appear to be abandoned. I know kadena[1] and cardano[2] are written in Haskell. There is also Aeternity[3], which is the only currency I know of written in Erlang. In the early days Charles Hoskinson apparently wanted Ethereum to be written in Scala. I don't think any of the core devs know Scala, but then again Charles Hoskinson was booted from the project so his language choice was dropped. Synereo was to be written in Scala, but the founders (the CEO and the CTO) split in December. The CEO doesn't want Synereo to make a blockchain anymore, he wants to make some kind of escrow for ponzi schemes. I hear from the devs they want to code the thing in javascript. The CTO is making something called RChain; I heard he wants to use some pi-calculus interpreter he wrote in C90 back when he worked at Miter corporation in the 90s, but maybe he's ditching that. From job postings I can see MaidSafe is looking for Rust programmers. MaidSafe has been in R&D for a decade, so they must have had yet another pivot recently. To be frank, while there are functional programmers in the scene, these guys are struggling to establish themselves. There's a lot more talent in procedural programming which is why so much code is written in those languages. I'm not 100% that functional code is going to have fewer bugs which result in financial exploits. [1] http://kadena.io/ http://kadena.io/ [2] https://iohk.io/projects/cardano/ https://iohk.io/projects/cardano/ [3] https://github.com/aeternity https://github.com/aeternity
- steveklabnik 10y agoMaidSafe moved to Rust in 2015 https://blog.maidsafe.net/2015/07/01/the-ants-are-coming/ https://blog.maidsafe.net/2015/07/01/the-ants-are-coming/ I gave a talk with a summary of why they switched from C++ as part of this general talk on production Rust last year: https://www.infoq.com/presentations/rust-production https://www.infoq.com/presentations/rust-production
- tyingq 10y agoThis wasn't an exploit of that type though. I assume Rust allows for the same type of error? Not familiar with Rust, but does the following work?: let mut x = 0; if x = 1 { println!("oops, meant =="); }
- aethertap 10y agoActually the type system catches that particular mistake: error[E0308]: mismatched types --> src/main.rs:5:6 | 5 | if x = 1 { | ^^^^^ expected bool, found () | = note: expected type `bool` = note: found type `()` error: aborting due to previous error error: Could not compile `playground`. To learn more, run the command again with --verbose.
- tyingq 10y agoInteresting. Is there any plausible way that Rust can fall into the == vs = trap?
- aethertap 10y agoI haven't yet reached the level of Rust mastery where I'm confident in this answer, but as far as I can tell it's very hard to make that kind of mistake. I'd be very interested to hear what others have to say on it though.
- steveklabnik 10y agoNo, as assignment always results in (), and if always requires a boolean. This is by design.
- tyingq 10y agoAh...so this works: fn main() { let mut x = false; println!("{}", x); if {x=true;x} { println!("{}", x); } } But stands out as pretty obvious. Not something you might easily sneak into a codebase.
- aeternity 10y agoThis is exactly the reason why we are doing a new blockchain from scratch in Erlang; also with a lispy dialect for smart contracts. æternity is a new blockchain for scalable smart contracts interfacing with real-world data via a decentralized oracle. Smart contracts are essentially pure functions here. We have also a compiler for a Lispy language. Check out our whitepaper (www.aeternity.com) and check out our Github ( github.com/aeternity/testnet ) (also check the /docs folder). Disclaimer: I am the founder of aeternity.
- CyberDildonics 10y agoHello world in Rust is still 2.5MB if you statically compile all the libraries in since it doesn't strip unused functions. The tools and ecosystem are nowhere near what they are for C++
- steveklabnik 10y agoIf this matters to you, it's not hard to get it down to something much smaller.
- CyberDildonics 10y agoOf course it matters and I've tried. Using nostdlib wipes out everything, so it becomes all or nothing, which is the problem.
- aij 10y ago> Hello world in Rust is still 2.5MB if you statically compile all the libraries in Still? Since when? Last I checked it was 661kB for Rust vs 829kB for C, and that was quite a while ago. http://stackoverflow.com/a/29461455/2343847 http://stackoverflow.com/a/29461455/2343847
- CyberDildonics 10y agoTo be clear, you think that 829kB is the size of a statically linked C program that uses printf to print 'hello world'? In visual studio it is 25KB - 40KB. All of musl compiles to under 500KB.
- Shorel 10y agoWhat? I have done hello world in C at about 4kB. You may be confusing C with C++.