[HN Gopher] Confession Of A C/C++ Programmer (2017)
       ___________________________________________________________________
        
       Confession Of A C/C++ Programmer (2017)
        
       Author : yagizdegirmenci
       Score  : 56 points
       Date   : 2021-01-25 15:19 UTC (7 hours ago)
        
 (HTM) web link (robert.ocallahan.org)
 (TXT) w3m dump (robert.ocallahan.org)
        
       | Nursie wrote:
       | >> I cannot consistently write safe C/C++ code.
       | 
       | I think it's going to depend on your attack surface. Could I sit
       | down and write a web-facing server from scratch and have a
       | reasonable expectation of safety? Probably not. Can I write a
       | piece of firmware for an embedded device with no internet access
       | and a very limited serial protocol, and have a reasonable
       | expectation of that being 'safe'? That seems more likely,
       | particularly if I follow good practice and use available analysis
       | tools where possible.
       | 
       | I think the biggest problem with these languages is that when
       | something goes wrong (as it so often does), the keys to the
       | kingdom are up for grabs as the whole of everything can suddenly
       | be manipulated, to read out arbitrary memory (e.g. heartbleed)
        
         | mumblemumble wrote:
         | It almost goes both ways. Yes, being on an embedded device with
         | no Internet access reduces your external attack surface. But it
         | also limits your ability to use lots of newer language features
         | designed to improve safety, because those features often cost
         | CPU cycles or memory.
         | 
         | My (completely uninformed) guess is that most of any net
         | benefit from being on an embedded system comes from the simple
         | fact that "embedded" implies "constrained", which implies "less
         | code," which, in turn, implies "fewer opportunities to create
         | bugs in the first place."
        
           | Nursie wrote:
           | It certainly plays into it - fewer moving parts means less
           | opportunity for things going wrong.
        
       | [deleted]
        
       | aledthemathguy wrote:
       | Layman warning: I never really understood (as an outsider who
       | does not code) why code _can_ be unsafe. Is code more like art
       | (painting) than math (writing an equation which balances itself)?
        
         | dozzman wrote:
         | I don't know about the art vs math question but, taking the
         | math example, your code can be unsafe in the same way your
         | maths can be wrong (i.e. maybe you start with a bad premise or
         | your derivation is invalid). More generally I'd describe both
         | of these situations as 'unsound' and actually they manifest
         | themselves in the same way in both disciplines (an oversight,
         | incorrect model, complexity, etc).
         | 
         | You might think that if you do maths on the computer, maybe it
         | can help you keep things valid as you execute your derivations,
         | and something similar can be done for coding. This is true, in
         | maths/logic they have theorem provers and in coding we have
         | _static typing_. Again they literally manifest themselves in
         | the same way in both disciplines due to the Curry-Howard
         | Correspondence[1].
         | 
         | You can also argue that in conjunction with static typing there
         | are also linters, etc, but I anchor specifically to static
         | typing in this example because of how directly it relates to
         | your math comparison.
         | 
         | [1]:
         | https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspon...
         | 
         | EDIT: spelling
        
         | ASalazarMX wrote:
         | Compare it with tax law: lawyers, legislators, and many other
         | people dedicate enormous amounts of time to create tax laws,
         | and still tax evaders (hackers) find loopholes to exploit.
         | Those loopholes are the law's bugs.
         | 
         | One could argue that those loopholes are left intentionally
         | (back doors), but even if all actors were honest, bugs would
         | still happen from time to time.
         | 
         | Computer code has even more bugs because it is produced
         | massively and quickly, without the bureaucracy of tax code.
         | Anyone can create an awesome
         | application/library/framework/etc., and share it freely with
         | the world. People end up using these projects as stepping
         | stones for their own projects, creating a complex layered cake
         | where bugs can hide for years.
        
         | mden wrote:
         | I think it's more like laws (of man, not nature) than art or
         | math. There are complex rules that define how a computer and a
         | programming language on that computer function. Even if we
         | assume these rules are perfectly defined and not bug-ridden the
         | programmer still needs to understand them and write contracts
         | (code) with no logic errors that can lead to any number of
         | disastrous scenarios such as data-loss, data-corruption, or
         | data-leaking among others.
         | 
         | Take this immense complexity of the computer and the
         | programming language and complex it further with requirements
         | for the business problem being solved and throw in a tight
         | deadline and you have a recipe which leads to the vast majority
         | of code being buggy.
        
         | dmytrish wrote:
         | "unsafety" is a very overloaded term. In this context, one
         | specific technical meaning is assumed: _memory safety_ [0] (not
         | type safety, not safety from hacking, etc, although they do
         | depend on memory safety).
         | 
         | Programming languages are tools for building abstractions and
         | concrete implementation of abstractions. They are very rarely
         | verified and described mathematically and exhaustively; it is
         | possible to state some properties of some programs, but it is
         | mathematically impossible to state any meaningful property for
         | an arbitrary program [1].
         | 
         | However, it is possible to constrain used abstractions in a way
         | that allows to uphold some properties (to some degree). Memory
         | safety of a language means that a program in that language can
         | change a variable/state if and only if it "touches" it
         | semantically (e.g. via a valid pointer/reference). A memory-
         | safe language creates a reliable "abstraction cage" for
         | (almost) any program written in it that guarantees (but not
         | necessarily mathematically) that unrelated variables cannot be
         | changed. "Glitches in the Matrix" (changing one variable
         | magically changes a random other one) are still possible, but
         | very rare in practice. Examples: Java/Python (which incur
         | significant inefficiency when executing a program), and
         | recently (the safe part of) Rust, which often comes very close
         | to C/C++ in efficiency while retaining memory safety in most of
         | its code.
         | 
         | C/C++ are examples of memory unsafe languages: their memory
         | abstractions are not even close to an "abstraction
         | cage"/"Matrix", they are just thin "guardrails" and guides, not
         | enforceable rules: it is easy to read/corrupt an unrelated
         | variable in a program (sometimes even via a malicious input to
         | a program). This design choice was semi-deliberate: C/C++ solve
         | the task of programming existing computer hardware efficiently
         | and nobody knew how to create a practical, efficient and
         | memory-safe systems programming language even twenty years ago.
         | It is possible for a coder to code "defensively", using
         | empirical best practices and tools for reducing possibility of
         | using program memory incorrectly. C++ has a subset and tooling
         | that comes tantalizingly close to memory safety, but it is
         | still a costly uphill battle and even the best C/C++
         | coders/organizations fail to avoid memory misuse.
         | 
         | [0]: https://en.wikipedia.org/wiki/Memory_safety [1]:
         | https://en.wikipedia.org/wiki/Rice%27s_theorem
        
         | jcranmer wrote:
         | In mathematics, you need to assert a set of axioms (or
         | preconditions) under which the theorem is held to be true.
         | These axioms can be challenging to figure out; naive set theory
         | was destroyed by Russel's paradox. Rather famously, the axiom
         | of choice is equivalent (in the sense that assuming one, one
         | can prove the other) with the well-ordering principle, and yet
         | one is "obviously" true and the other is "obviously" false.
         | 
         | Euclid proved a lot of statements in geometry using several
         | axioms, but the last one was clunky and seemed to be something
         | that ought to be a theorem instead: this held that, given a
         | line and a point not on that line, there was exactly one other
         | line that was parallel to the first line passing through said
         | point. Eventually, though, it was found that there was a
         | reasonable interpretation of geometry where that axiom is _not_
         | true, whence spherical geometry (parallel lines do not exist)
         | and hyperbolic geometry (many lines can pass through that point
         | and remain parallel).
         | 
         | Another example is in physics: the Crystallographic Restriction
         | Theorem mathematically restricts the kind of forms that
         | crystals could form in. And yet, in the 1980s, several crystals
         | were demonstrated which had five-fold symmetry, which is
         | forbidden by that theorem. The issue is that theorem
         | presupposes that crystals need to be symmetric under linear
         | translations, but there exist forced tilings that have
         | rotational symmetry but not translational symmetry--and these
         | can have five-fold symmetry. (We now call these quasicrystals).
         | 
         | In CS, "unsafe code" amounts to code where programmers did not
         | assert all of the possible preconditions to their code. In
         | contrast to much of mathematics, failing to assert all of the
         | preconditions for safety is remarkably easy in some languages,
         | chiefly C/C++.
        
         | lbrandy wrote:
         | Software is more like building a machine than either math or
         | art. There've been attempts to make formally-provable programs
         | (so it _is_ like math) but these are not in widespread use.
         | 
         | Go watch the Lockpicking Lawyer on youtube pick locks and
         | trivially crack/open every lock ever made. This is, roughly,
         | the best physical analog to what happens with computer programs
         | and safety. The creators are trying but they have to be correct
         | everywhere, from every angle, and the attacker only needs to
         | find one weakness to break it.
        
         | gnulinux wrote:
         | Imagine writing code for an elevator. If there is a glitch in
         | your code such that when the date changes from 1999 to 2000
         | it'll release all the ropes... that'd cause bunch of people to
         | die. Something like this is exceptionally unlikely, but if
         | you're writing code for a real life device you should always
         | always think about its implications.
         | 
         | Read this: https://en.wikipedia.org/wiki/Therac-25
         | 
         | This Radiotherapy machine had a software bug which caused 6
         | people to be given massive radiation overdose.
        
         | traverseda wrote:
         | Ever seen a 3D printer in operation?
         | 
         | 3D printers use a "language" called gcode. It's not really
         | programming, it's a series of commands that tell the 3D printer
         | nozzle to move to a certain location at a certain speed while
         | extruding at a certain rate. There are a lot of ways you can
         | mess that up, you can tell the nozzle to go as low as it can
         | and just start extruding, giving you a big blob on the bottom
         | of your 3D printer. You can tell it to move to a position that
         | it physically can't, outside of the bounding box it can print
         | in. Most 3D printers don't have endstops to prevent you from
         | going too high on an axis, so they'll try to do that and tear
         | themselves apart. You can try to extrude while your extruder
         | isn't up to heat and grind down your filament. You can
         | physically jam your extruder into whatever it is you're
         | printing. There are all kinds of things that 3D printers are
         | physically capable of doing that are unsafe.
         | 
         | Computers are just a machine like a 3D printer. You're
         | "physically" moving bytes of data around (that's where most of
         | the heat comes from), doing operations on them, etc. Nowadays
         | you generally can't get them to destroy themselves but in the
         | earlier history you absolutely could tell the machines to tear
         | themselves apart in the same way you can tell a 3D printer to
         | tear itself apart.
         | 
         | Computers are just machines for moving bytes around, and it's
         | really hard to make a machine that you can only do safe stuff
         | with.
        
         | tacitusarc wrote:
         | When programmers call code unsafe, what they mean is the code
         | can be unpredictable, and unpredictability leads to
         | unintentional behaviors, which are generally bad since good
         | behaviors are intentional. Code can be unpredictable because
         | it's not written in a vacuum. Not only does code exist within
         | the context of other code, it exists within the context of a
         | compiler or interpreter, possibly a runtime, an operating
         | system and firmware, a CPU architecture and memory and disk and
         | networking and, of course, user input. All of these things make
         | for an incredibly complex system, and incredibly complex
         | systems produce emergent behaviors. So it is very difficult to
         | work within such a system and add behaviors to it without
         | creating unintended consequences. This is especially true the
         | more complex the interactions of the components of the system,
         | and c/c++ allow for very complex interactions. There's more to
         | it than that of course, but I think that's what underlies most
         | of it.
        
         | extrememota wrote:
         | The code can be unsafe because it is physically impossible to
         | test for every input in a computer. This is where various
         | engineering designs come in which reduce the area of testing
         | based on some theories.
         | 
         | Also, even in math, there are enough mistakes in publications
         | (not just typos, but reasoning errors) which hopefully do not
         | affect the eventual results in any fundamental way. The
         | equivalent of safe code in computer science would be equivalent
         | of completely formal proofs in mathematics (like in Coq and
         | similar languages), but probably much more difficult due to
         | existence of temporal conditions.
        
         | CodeGlitch wrote:
         | Simplest example I can think of:
         | 
         | Your maths function takes a variable and divides by that
         | variable. What happens if that variable is set to zero?
        
         | nickysielicki wrote:
         | https://www.usenix.org/system/files/1311_05-08_mickens.pdf
        
         | PartiallyTyped wrote:
         | Programming is a craft. In the same way the pentagon and white
         | house have structural proofs against certain kinds of attacks,
         | programs have certain kinds of defences against certain kinds
         | of attacks.
         | 
         | Defences are necessary when the program interacts with users or
         | external inputs of any form. This can be inputs in the form of
         | text or files, or even by interfacing with a program, e.g. the
         | malicious code executes system code in a specific manner to
         | cause certain side effects.
        
         | jodrellblank wrote:
         | Ever seen one of those prank videos where someone is in the
         | shower rinsing shampoo off their head, and the prankster leans
         | over the shower wall and squirts a bit more shampoo onto their
         | head, and the prankee gets more confused and annoyed when they
         | keep rinsing "endless" amounts of shampoo that should be done
         | by now?
         | 
         | Buffer overflow and "unsafe" code is like that - the showering
         | person isn't painting or equating, they're expecting an end
         | condition "when the water coming off my head stops having soapy
         | lather and runs clear" which works every time, but is not a
         | "safe" pattern - it assumes no malicious intervention. Someone
         | else can change the surrounding circumstances so that the end
         | condition doesn't happen when it should, and "cause" the rinse
         | routine to keep running for longer and longer.
         | 
         | Buffer overflow attacks are like this, they're expecting to
         | read some data and stop when they get to an end condition; when
         | badly designed an attacker can change something to delay the
         | end condition and cause more data to be read. Inside a computer
         | there are no such things as "separate applications" or
         | "security boundaries" or "program data" or "OS instructions",
         | except that the patterns of numbers are supposed to be
         | interpreted as those things. If a program can write "program
         | data" but cannot give the OS instructions, maybe it can drop
         | some more shampoo on the OS's head and cause the OS to keep
         | reading more and more "OS instructions" only it's now reading
         | past the normally expected end and reading into the "program
         | data" location, and the same numbers which were once "safe
         | program data" are becoming "OS instructions" to be executed by
         | the OS using its OS permissions, which the program had no
         | original rights to do. Breaking the imaginary security boundary
         | by exploiting the assumptions baked into some other code that
         | is running.
        
         | ninkendo wrote:
         | Imagine trying to assign a unique number to every bit of data
         | your program uses, including stuff like text, pictures, etc.
         | Such that some text that uses 100 bytes uses 100 numbers, a
         | picture with 1,000,000 byte uses 1,000,000 numbers, etc.
         | 
         | You can just say "Start at number 0 and create a new number for
         | each bit of data", but then maybe that JPEG your program uses
         | occupies the same set of numbers as the text you're writing to.
         | So you need to make sure it's all _unique_ , and that each
         | logical thing you're storing gets its own unique set of
         | numbers. Easy enough, except data changes as your program runs,
         | so every now and then you need to say "ok there's not enough
         | space to store this thing, so I'm going to assign it a new
         | number so that it doesn't conflict with this other data I
         | have."
         | 
         | That works well enough, except what if parts of your software
         | do stuff like "write value X to number 103820"? Will that do
         | what you want? Maybe that code is responsible for updating some
         | text somewhere, but what if that text grew too big and moved
         | somewhere else? How do you know if the number it's writing to
         | is actually the right text?
         | 
         | What's way worse, is that some of these numbers are used by the
         | processor for bookkeeping on things like "what was the last bit
         | of code I was executing before I ran this code?" and if you
         | overwrite _those_ numbers, you can cause the processor to do
         | evil things.
         | 
         | That's memory safety. It's the idea that, if you just let code
         | write to arbitrary locations in memory, it's very very
         | difficult to do this safely. The answer ends up being to have
         | languages that simply _don 't let you do that_, and that's a
         | big step towards having safe code. "Safe" languages instead
         | only let you do things like "append to this data", which will
         | automatically move the data to another address if it's too big.
         | But they won't let you just write to arbitrary addresses. Even
         | "Safer" languages ensure that one thread can't be in the middle
         | of moving some data to a new address while another thread is
         | trying to write to it, etc etc.
         | 
         | So to your question, it's very much like painting in that
         | regard. If you start on one corner of the canvas and draw
         | something way too big and don't leave yourself enough room,
         | you'll paint over parts of the painting you wanted to keep.
         | Since programs are super dynamic, the problem of making
         | everything has enough space to be represented in a real
         | computer, ends up being kinda hard, and the way older languages
         | are designed can sometimes make it nearly impossible.
        
       | zabzonk wrote:
       | But can you write "consistently safe" (whatever that may mean)
       | programs in any other language?
        
         | oytis wrote:
         | Should be a bit easier with Rust or Ada I think.
        
         | [deleted]
        
         | jerf wrote:
         | Obviously, this depends on your definition of "safe".
         | 
         | But there's a fairly large set of "safety" issues that, in
         | 2021, effectively _only_ C and C++ have. Other than straight
         | assembler, which by its nature will always be with us in some
         | sense, there aren 't any other languages in common use anymore
         | with similar memory safety issues. I'm not sure I can think of
         | any other languages with "pointer arithmetic". Almost nobody
         | else is using NULL-terminated strings. And so on and so on.
         | 
         | (Please read that carefully. I'm not saying every language
         | other than C and C++ are completely safe by any definition. I'm
         | saying there are significant weaknesses that _only_ C and C++
         | have nowadays. Threads unsafety, mutable state management
         | issues, bad /unhelpful type systems, plenty of common unsafety
         | out there today, but C/C++ have their own nearly-unique entries
         | on that list.)
         | 
         | C++ nominally has solutions to any given weakness, but in
         | practice they're at the very least difficult to use in
         | isolation, and very, very complicated to completely correctly
         | use in combination with each other, to say nothing of code
         | bases that inevitably end up having to deal with multiple
         | solutions intersecting in the same code base because of two
         | important libraries that have to do things differently or
         | whatever.
        
           | zabzonk wrote:
           | There are lots of languages that are not "safe" in your
           | terms. I'll limit them to ones I am fairly expert in -
           | assembler, FORTH, Object Pascal, but there are many, many
           | others.
        
             | jerf wrote:
             | FORTH and Object Pascal are not in _common_ use.
             | 
             | Languages actually 100% dying are rare. I'm very, very
             | confident that there are people out there working in them
             | full time, and making a good living.
             | 
             | But they are not even remotely in the same tier as Java,
             | Python, Go, C++, C, Objective C, etc.
             | 
             | Again, this depends on your definition of "common", but...
             | can anyone tell me with a straight face that Java and FORTH
             | are in the same class of usage?
             | 
             | Also, I already called out assembler as an exception. By
             | its nature it will always be unsafe. This is fine by me,
             | because any restriction that it lays down will be something
             | that _no_ language above it can possibly get around, no
             | matter how good an idea that may become in a future, which
             | is dangerously restrictive over the long term. I don 't
             | look to assembler to provide language-level safety. I don't
             | _want_ assembler to, say, rigidly protect the  "private"
             | fields of objects from exterior access, because then my
             | debuggers and state viewers and other tools become
             | impossible.
        
             | pjmlp wrote:
             | Object Pascal is definitly safer.
             | 
             | - bounds checking
             | 
             | - proper strings
             | 
             | - strong typed enumerations
             | 
             | - parameter references cannot be forced to nil (C++ ones
             | can be tricked into null and C doesn't have them anyway)
        
           | bluetomcat wrote:
           | C is assembly on steroids which gives you just the essential
           | features of an HLL, without any of the fancy stuff which
           | would complicate the translation and would potentially
           | require a runtime environment.
           | 
           | Any C construct/operation has a canonical representation as a
           | short series of instructions found on most machines.
           | Essentially, what you get is expression-oriented syntax
           | (operations are expressions yielding a result), support for
           | structured programming (loops, conditionals), automatic
           | register allocation and stack frame management through named
           | local variables, abstraction for calling conventions and a
           | rudimentary type system around integers and pointers.
        
       | masklinn wrote:
       | > I've heard maybe Daniel J. Bernstein can
       | 
       | DJB simply redefines his unsafe code as safe[0] and asserts that
       | you're Using It Wrong:
       | 
       | --
       | 
       | In May 2005, Georgi Guninski published "64 bit qmail fun", three
       | vulnerabilities in qmail (CVE-2005-1513, CVE-2005-1514,
       | CVE-2005-1515):
       | http://www.guninski.com/where_do_you_want_billg_to_go_today_...
       | 
       | Surprisingly, we re-discovered these vulnerabilities during a
       | recent qmail audit; they have never been fixed because, as stated
       | by qmail's author Daniel J. Bernstein (in
       | https://cr.yp.to/qmail/guarantee.html):
       | 
       | > This claim is denied. Nobody gives gigabytes of memory to each
       | qmail-smtpd process, so there is no problem with qmail's
       | assumption that allocated array lengths fit comfortably into 32
       | bits.
       | 
       | Indeed, the memory consumption of each qmail-smtpd process is
       | severely limited by default (by qmail-smtpd's startup script);
       | for example, on Debian 10 (the latest stable release), it is
       | limited to roughly 7MB.
       | 
       | Unfortunately, we discovered that these vulnerabilities also
       | affect qmail-local, which is reachable remotely and is not
       | memory-limited by default (we investigated many qmail packages,
       | and _all_ of them limit qmail-smtpd 's memory, but _none_ of them
       | limits qmail-local 's memory).
       | 
       | As a proof of concept, we developed a reliable, local and remote
       | exploit against Debian's qmail package in its default
       | configuration. This proof of concept requires 4GB of disk space
       | and 8GB of memory, and allows an attacker to execute arbitrary
       | shell commands as any user, except root (and a few system users
       | who do not own their home directory). We will publish our proof-
       | of-concept exploit in the near future.
       | 
       | About our new discovery, Daniel J. Bernstein issues the following
       | statement:
       | 
       | > https://cr.yp.to/qmail/guarantee.html has for many years
       | mentioned qmail's assumption that allocated array lengths fit
       | comfortably into 32 bits. I run each qmail service under
       | softlimit -m12345678, and I recommend the same for other
       | installations.
       | 
       | --
       | 
       | [0] https://www.openwall.com/lists/oss-security/2020/05/19/8
       | 
       | PS: HN's markup keeps sucking and making comments unreadable
        
         | knorker wrote:
         | In other words the instructions on how to run qmail without
         | security holes were clearly displayed in the bottom of a locked
         | filing cabinet stuck in a disused lavatory with a sign on the
         | door saying 'Beware of the Leopard.
        
         | cratermoon wrote:
         | "Nobody gives gigabytes of memory to each qmail-smtpd process"?
         | 
         | -----
         | 
         | QUESTION: "I read in a newspaper that in l981 you said '640K of
         | memory should be enough for anybody.' What did you mean when
         | you said this?"
         | 
         | ANSWER: "I've said some stupid things and some wrong things,
         | but not that. No one involved in computers would ever say that
         | a certain amount of memory is enough for all time."
         | 
         | https://www.wired.com/1997/01/did-gates-really-say-640k-is-e...
         | 
         | -----
         | 
         | If I were a cynical programmer I might think DJB just doesn't
         | want to hand over a $500 check.
        
       | tuckerpo wrote:
       | Plethora of static analysis tools make it possible to write code
       | that's "safe enough" I would imagine, for some value of "safe
       | enough"
        
         | felixguendling wrote:
         | Don't forget Sanitizers combined with comprehensive test suits.
         | I would always recommend doing both, static and dynamic
         | analysis.
        
         | pjmlp wrote:
         | Now if people would actually use them.
         | 
         | > Which of the following tools do you or your team use for
         | guideline enforcement or other code quality or analysis?
         | 
         | https://www.jetbrains.com/lp/devecosystem-2020/cpp/
         | 
         | With the best value being 36%.
        
         | staticassertion wrote:
         | Then why have we seen ITW exploits against Chrome, or Linux?
         | These are C and C++ codebases that undergo tons of static
         | analysis and testing - tons of research goes into both of those
         | projects to make them safer.
         | 
         | Still vulns. Still exploits.
        
       | password321 wrote:
       | I'm guessing this post is another low-key Rust promotion.
        
         | pjmlp wrote:
         | There are plenty of safe alternatives.
        
       | dang wrote:
       | Discussed at the time:
       | https://news.ycombinator.com/item?id=14785867
        
       | beached_whale wrote:
       | One nice thing about newer C++ is that you can write safer(in
       | some sense) functions. To a point. constexpr/consteval functions
       | that are tested at compile time do not have UB and do not
       | interact with global state. This is enforced by the compiler. So
       | building up from this, you get safer systems. One cannot say they
       | are safe though, as it is complicated.
       | 
       | This comes back to is the whole system safe, what do I trust, and
       | how have I mitigated my mistakes(there are always mistakes). No
       | purported safe system will stop me from making logic errors in my
       | conditionals. They will stop an access outside a valid objects or
       | ranges. But C++ also has tools to mitigate this, is a for loop
       | good here or should it be a function that works on a range and is
       | tested properly. Can I enforce my constraints in a type so that
       | the compiler does the work for me.
        
         | dvfjsdhgfv wrote:
         | > One nice thing about newer C++ is that you can write safer(in
         | some sense) functions.
         | 
         | But in practice you rarely find these in the codebase you
         | inherit.
        
           | beached_whale wrote:
           | That goes for any system, legacy code is good and bad. Often
           | it's battle hardened, but looks super complicated because of
           | the post release organic growth with fixes. Green projects
           | are able to be engineered nicely(if you have the time...) but
           | are missing real world exposure to find all our incorrect
           | assumptions and errors.
        
       | Out_of_Characte wrote:
       | Programming today is fundamentally designed to function rather
       | than be correct. correctness is the second stage that any
       | programmer experiences when you rewrite a naive implementation
       | and get a performance boost or behaviour that is less likely to
       | fail. but really all that has happend is any first completely new
       | implementation has unknown unknowns and rewriting it improves
       | your code and turns them into known unknowns. but there is still
       | tons of stuff that I dont understand that will fail for unknown
       | reasons. There's just hopefully less of them.
        
         | zoomablemind wrote:
         | > Programming today is fundamentally designed to function
         | rather than be correct...
         | 
         | As long as such code is coupled with reasonably complete tests
         | for the expected behavior (think of fuzzing as one of such
         | tests), it's a quite valid and "safe" approach.
         | 
         | Of course, it's possible to write "unsafe" code, yet pass most
         | of business-related tests. But this is equally possible with
         | any programming language.
         | 
         | Unsafe assumptions will lead to unsafe implementation.
        
       | OnlyOneCannolo wrote:
       | > I cannot consistently write safe C/C++ code.
       | 
       | There's a pretty big ecosystem of tools and techniques beyond
       | just the compiler for writing safe code. Unfortunately, they all
       | have usability issues, so the burden of writing safe programs
       | often falls almost entirely on the individual.
        
         | lasagnaphil wrote:
         | Valgrind helps a lot though, it usually solves my memory
         | errors. (If that doesn't do it, then it's either just a logic
         | bug, or you have a really strange bug in the first place!) The
         | main issue people have with it is that its terminal interface
         | is almost always unusable (you get thousands of lines of
         | gibberish text), and there aren't many good Valgrind GUI
         | frontends available. Thankfully CLion has an integrated
         | valgrind inspector that really helps a lot.
        
           | OnlyOneCannolo wrote:
           | Valgrind is good but it's a dynamic tool, so it won't catch
           | anything you don't exercise. There are better options, but
           | there are usually some extra barriers to using them.
           | 
           | By usability I also meant getting it to work for your setup
           | and learning how to use it.
        
       | xuhu wrote:
       | Rust looks like Facebook, while C++ looks like every publishing
       | system out there (Wordpress, Django, Drupal, MediaWiki, static
       | sites, etc).
       | 
       | You're a lot more restricted on FB but you also can't host your
       | online store, or really anything except: messages, groups,
       | events, photos and videos.
       | 
       | C++ could probably be more regulated for certain scenarios, but
       | if people don't paint self-hosted blogs as evil, why paint C++
       | that way ?
        
         | PartiallyTyped wrote:
         | Your analogy makes absolutely no sense.
         | 
         | There are operating systems written in rust. If that is
         | possible, then anything else is possible too.
        
         | munchbunny wrote:
         | _C++ could probably be more regulated for certain scenarios_
         | 
         | At that point, a different language might be better anyway.
         | 
         | My experiences with C++ (I dust it off every year because of
         | something that needs doing that nobody else wants to touch) are
         | that I've usually dipped into C++ specifically for some
         | combination of:
         | 
         | 1. Invoking API's that have been around for a long time,
         | usually meaning OS API's
         | 
         | 2. Hand-optimized performance sensitive code where, for
         | example, you're auditing every runtime memory allocation that
         | has to be done in the inner loops
         | 
         | 3. Modifying legacy code that's written in C++
         | 
         | In all of those cases you have to dip into unsafe territory
         | regularly, so you end up with pretty much what Rust does with
         | safe/unsafe, but with less in the way of the language helping
         | you to ferret out your memory handling bugs. Every time I do
         | it, even if I don't think I've created memory handling bugs,
         | and even when my tools don't catch anything, I always leave
         | with a low grade fear that my code will end up in a CVE
         | somewhere.
        
         | ivanbakel wrote:
         | Could you explain what you mean in more concrete terms? In what
         | way does Rust restrict the programmer so much that it's
         | comparable to the difference between an FB page and a site-
         | building system?
        
         | bilkow wrote:
         | That's really hyperbolic, I don't believe there's anything you
         | can do in C++ that you can't do in Rust.
         | 
         | Your argument seems a lot more valid for Python, Java, as AFAIK
         | in those languages you can't access raw memory.
         | 
         | Do you have a specific example?
        
           | MauranKilom wrote:
           | > I don't believe there's anything you can do in C++ that you
           | can't do in Rust.
           | 
           | I think you'll have to make "can do" more precise for this
           | question to have a meaningful answer. All mentioned languages
           | are Turing complete and thus equivalent on that level.
           | 
           | > you can't access raw memory.
           | 
           | I can wrap a file in a ByteBuffer in java and the JVM will
           | (make a best effort to) perform native I/O on that. Does that
           | pass as "access raw memory"? If not, you'd have to explain
           | how this is different from the abstract machine that C++ is
           | defined on.
           | 
           | Sure, in Java you can't escape the garbage collector, but in
           | C++ you also formally invoke UB if you violate the object
           | lifetime requirements (even though will generally work due to
           | this part of the standard still being... work in progress,
           | let's say).
        
             | bilkow wrote:
             | > I think you'll have to make "can do" more precise for
             | this question to have a meaningful answer. All mentioned
             | languages are Turing complete and thus equivalent on that
             | level.
             | 
             | I actually agree, I was just arguing with the point of the
             | above comment which implicated you can't do lots of things
             | in Rust that you can in C++. I don't know what the author
             | was referring to, so I can't be more specific.
             | 
             | > I can wrap a file in a ByteBuffer in java and the JVM
             | will (make a best effort to) perform native I/O on that.
             | Does that pass as "access raw memory"?
             | 
             | I was referring to directly accessing the memory "owned" by
             | local variables (the stack), the bytecode of the program
             | itself (on von Neumann architecture), etc. It was a
             | counterpoint in that implication that every other language
             | (akin to publishing systems) had no limitations where Rust
             | had. But I don't think that's actually a problem as (if
             | that's ever needed) you can FFI to another language that
             | can do that stuff and (as you said) all those languages are
             | turing complete.
             | 
             | Sorry if it sounded like I was attacking Java & Python, for
             | most applications I don't think the "runtime" limitation
             | isn't a problem and comparing them to facebook is still
             | hyperbolic.
        
       | lainga wrote:
       | Has this changed in 3 years? Was the author really writing about
       | modern C++, or C++ as he remembers it? One of the comments on
       | that post is pointing out the introduction of std::array with
       | C++11.
        
         | mumblemumble wrote:
         | Strictly speaking, it can never change. The features that
         | create safety pitfalls are still there, and they can never be
         | removed without breaking backward compatibility. And you can't
         | simply avoid using those features, because their use is baked
         | into the standard library, or into some other _de facto_
         | standard library that you can 't realistically live without.
        
       | RcouF1uZ4gsC wrote:
       | I have found that most people who classify themselves as a "C/C++
       | programmer" are incompetent at both C and C++.
       | 
       | There are many competent C and there are competent C++
       | programmers, but people who try to be C/C++ programmers end up
       | with the worst of both worlds. They lose the simplicity of C
       | without going far enough to gain the full benefits of C++.
        
         | tuckerpo wrote:
         | I've had to ping pong between C and C++17 on some projects
         | where I've written Linux kernel modules, and then userland C++
         | code to exercise said modules.
         | 
         | I find it very hard to transition back to a C mindset coming
         | from modern C++, not so much the other way around. Going from
         | kernel C to userland modern C++ is akin to getting that first
         | gasp of fresh air after nearly drowning.
         | 
         | Granted, that _could_ be a function of the "complexity" of
         | writing kernel code, in that it can take up a lot of mental
         | real estate, and there's less "risk" involved with userspace
         | code...
        
           | MauranKilom wrote:
           | But would you call yourself a C/C++ programmer? Or a C
           | programmer and C++ programmer?
        
             | pjmlp wrote:
             | In English / is an abbreviation for _and_.
             | 
             | An abbreviation widely accepted by several institutions
             | with a saying in programming language standards, only
             | people in forums get uptight about writing C/C++.
        
               | [deleted]
        
             | tuckerpo wrote:
             | I would call myself a programmer. No language prefix.
             | 
             | Languages are tools.
        
         | raghuveerdotnet wrote:
         | This is completely misguided. People who call themselves C/C++
         | Programmers are basically developers who are proficient in
         | Systems Programming and not necessarily C or C++. It just
         | happens to be that C and C++ were the only primetime options
         | until the likes of Go and Rust entered the scene.
         | 
         | Also if you know C++ to a decent enough extent, you are going
         | to have a certain level of command over C too. And there is no
         | reason why calling yourself a C/C++ Programmer should undermine
         | your proficiency in either of those languages.
         | 
         | Broad generalizations are generally bad.
        
           | pjmlp wrote:
           | Thankfully no ISO C++ official documents don't mention C/C++
           | anywhere, neither has Bjarne ever written such thing.
        
         | asveikau wrote:
         | I don't call myself a C/C++ programmer but I have done both
         | professionally, am productive in both, like them both.
         | 
         | I understand and appreciate where idioms differ and that there
         | are pros and cons to each.
        
         | pjmlp wrote:
         | I guess FANNG are full of such programmers given that they use
         | C/C++ everywhere on their docs.
        
         | flohofwoe wrote:
         | "C/C++" is a valid term for the common subset of C and C++.
         | Even if both are different languages, it's possible to write
         | code which is both valid C and valid C++ (but is a subset of
         | both languages). Usually the goal when writing "C/C++" is to
         | write C code that also compiles in C++ compilers (and this,
         | contrary to popular believe, is a very restricted subset of C,
         | and is almost a 3rd language).
         | 
         | Also, what else would you call yourself if you write both lots
         | of C++ code (for the job) and C code (for fun) ;)
        
           | zabzonk wrote:
           | I would call myself a C and a C++ programmer. If I also wrote
           | Java (which I do), I would call myself a C, C++ and Java
           | programmer.
        
         | zabzonk wrote:
         | I agree that people that think there is a language called C/C++
         | probably don't have much of a clue, but it is certainly
         | possible to program in both C and C++ and do a good job in
         | both.
        
           | jstimpfle wrote:
           | In my perception there is a group of considerable size who
           | thinks that C++ is largely b* _s*_ , but still uses C++
           | (technically) for one reason or another (availability of
           | compilers, interfacing with existing ecosystems, availability
           | of jobs) - in a way that is basically C with almost no C++
           | features.
           | 
           | This is a group of people that considers themselves _systems
           | programmers_ in the first place, and doesn 't really care
           | about the language very much, except that they don't want to
           | have to deal with stuff like this:
           | https://twitter.com/fabynou/status/784905829866614784
           | 
           | I don't see any reasons for the people in this group to not
           | consider them "C/C++ programmers". Au contraire, I've found
           | the people that like to point out that "C/C++ isn't a
           | language" to be annoying nit-pickers that care too much about
           | the language and too little about systems programming.
        
           | flohofwoe wrote:
           | The common subset of C and C++ is different enough from
           | "idiomatic" C and C++ that it almost can be called a separate
           | "C/C++" language ;)
        
             | zabzonk wrote:
             | The common subset should probably be called something like
             | "better C" - it won't be able to use any major (or many
             | minor) C++ features. Basically, it will be ANSI C (give or
             | take). Noticeably, the code for the 2nd Ed of The C
             | Programming Language was tested using a C++ compiler, not a
             | C compiler
        
               | flohofwoe wrote:
               | The common C/C++ subset is an outdated and non-standard C
               | though. For instance standard-conforming C++ compilers
               | cannot compile C99 code and onward, they're stuck at a
               | non-standard C version that would roughly be C95, minus
               | some things that are valid C but not valid C++.
        
       | 0xTJ wrote:
       | Everyone makes mistakes, but trying to write correct code is
       | important. You have to be conscious of the consequences of what
       | you write. You shouldn't rely on non-fixed-width types having
       | specific lengths or on signed integer overflow, unless your code
       | guarantees that things will work (preprocessor/static_assert
       | checks against standard/compiler-specific properties). The worst
       | offenders I see often is violating aliasing rules, especially in
       | ways that could cause alignment issues.
       | 
       | In C, function isn't an object, you can't convert a function
       | pointer as a void pointer and back, and use it. Yet I've seen
       | that done many times, and it's probably safe on things that act
       | as if they have a von Neumann architecture.
       | 
       | If I'm relying on implementation-dependent functionality, I try
       | to make it so that whatever it is will fail to compile instead of
       | having incorrect behaviour.
        
         | gpderetta wrote:
         | > In C, function isn't an object, you can't convert a function
         | pointer as a void pointer and back, and use it.
         | 
         | It is not defined by the C standard, but POSIX requires it. So
         | any environment (including the compiler) claiming POSIX
         | conformance must support it.
         | 
         | Not sure how it works on Itanium though as, IIRC, function
         | pointers there are twice as wide as normal pointers.
        
         | zabzonk wrote:
         | Better than you being aware, make sure your build system is
         | aware - for example, compile your code with the maximum level
         | of warnings and errors turned on, and don't commit it until you
         | have resolved them all.
        
           | zoomablemind wrote:
           | +1. Yet this should be done from the very start of the
           | project.
           | 
           | Too often projects start in a permissive way, and then get
           | released. At that point switching to strict way may become an
           | unsurmountable task practically or politically.
        
       ___________________________________________________________________
       (page generated 2021-01-25 23:02 UTC)