How Do You Know Your Code is Secure?
bvc writes "Marucs Ranum notes that 'It's really hard to tell the difference between a program that works and one that just appears to work.' He explains that he just recently found a buffer overflow in Firewall Toolkit (FWTK), code that he wrote back in 1994. How do you go about making sure your code is secure? Especially if you have to write in a language like C or C++?"
Just get others to formally review it so if anything is found, there's collective responsibilty
I get mine verified by microsoft
Secure?? What does it mean?
I hit it with a shovel. If the code doesn't fall apart, I know it's pretty securely attached to my computer. If not, I add more epoxy glue.
... and then they built the supercollider.
Modern C++ provides a very nice and functional Standard Library which provides a lot of functionality and data structures such as strings, vectors, lists, maps, sets. While using these available classes does not completely rule out making programming mistakes related to buffer overflows and such, it at least minimizes the risk of producing stupid buffer overflow through badly done string handling. At least that's what my experience is.
Actually, the best thing would be not to use C or C++ at all, but that's where reality comes into play. Most developers don't even have the choice which language they should use, but that is predetermined by the employer and/or supervisor.
A monkey is doing the real work for me.
You introduce buffer overflows when you deal with buffers directly. In conventional C with its standard library you're encouraged to do this rather a lot, for example many of the string functions expect you to allocate a char buffer of big enough size and pass it in. The language's arrays are just syntactic sugar for accessing raw memory, with no bounds checks.
However you don't have to do it like this, especially not in C++ which has a safe string class (for example) as part of its standard library. Unfortunately C++'s vector type still doesn't do bounds checking with the usual [] dereferencing - you have to call the at() method if you want to be safe. But the general principle is: don't do memory management yourself, use some higher-level library (which exist for C too) and let someone else do the memory management for you.
You can write a C++ program and be pretty confident it doesn't have buffer overruns simply because it doesn't use pointers or fixed-size buffers, but relies on the resizable standard library containers.
-- Ed Avis ed@membled.com
I don't. I just open source my code, and other people find the security bugs for me. More eyeballs and all, ya know?
;)
The Online Slang Dictionary
Writting in C/C++ doesn't do the whole thing better. A strong/typed language like Delphi or a managed language like C# are less likely to have any buffer overflow type bugs, etc, but you never know. Code writting is not pizza baking.
It's time to realise that Abble's products are the biggest abomination these days. Just say NO to the dumb iAbble way!!
Easy, I never ever run the program.
0) Don't "roll your own" security unless absolutely necessary. Find someone else's implementations and work with those.
1) Design the code for security, code to that design. I've seen of security bugs creep into code because it was never designed to be secure.
2) Use static code checkers--such as Splint for C/C++ and FindBugs for Java--that look for security vulnerabilities.
3) Peer reviews/code audits. Sit down with your code (and have others who know how to look for security vulnerabilities sit down with your code) and do a full review.
Nothing is foolproof, but every little bit helps. It should be noted that all of the above also improve the overall quality of the code and reduce the number of overall bugs: Finding existent implementations of features that can be used can reduce maintenance and reduce bugs; Designing the code and putting it through a proper design review can catch a lot of logic problems and ensure that the code fits the requirements list--I've seen a huge number of synchronization bugs in Java simply because the author didn't know how to use synchronization properly; static code checkers find a lot more than just security bugs; and Peer Reviews/Code Audits can help isolate a variety of problems.
Integrate Keynote and LaTeX
Anyone who develops software knows the axiom - the number of bugs discovered in any piece of software is directly proportional to the amount of testing you perform on that software. From this, it follows that you can keep testing forever and at best only asymptotically approach bug-free code. Sounds hyperbolic, but I've observed it to be true in my experience. And as long as there are bugs, there are bound to be security bugs.
You can only minimize the risk that security issues will be found with any software. The best way to do this is to perform a rigorous code audit, preferably by security professionals. And if you can, make the software open source. You get a lot more eyes staring at it for free that way.
It's not that C/C++ is so insecure by itself, the problem is that programmers may not have used the best programming practices. There are plenty of libraries for handling strings and memory allocation in C, in C++ there are string and storage classes that do as much or as little checking as you need.
When you are an expert programmer there are places where you need more efficiency than the super-safe string routines can give you. It's the job of the expert to determine exactly how to balance efficiency against security, and only C/C++ can give you this balance.
You cannot know for sure (unless you want to develop code by mathematical proof, which requires a considerable amount of effort). However, you can do some things to help prevent buffer overflows and security problems in general: - encapsulate all buffer access, and make the interface overflow-safe. Then you need only ensure your encapulation is secure. - use a static code analysis tool that detects buffer overflows. I do not know of any open source ones off the top of my head, but I remember seeing an article on slashdot a few months ago about a new open source static analysis tool - avoid unsafe functions. Nearly all standard C functions that deal with buffers are unsafe (that is, a typo or oversight can give you a difficult to detect buffer overflow). Sprintf and strcpy are common culprits off the top of my head. If you're writing for Windows, the Microsoft extensions to the standard library have equivalent 'secure' functions (usually postfixed with _s). I do not know if there is an open source equivalent. - Use your compiler's buffer overrun detection. I think this is -fmudflap for gcc. That's all I can think of for now.
Easy! It doesn't run
By using valgrind. It's a virtual machine of sorts that runs your code and checks for any memory problems at all, including use of uninitialized memory. Combine that with thorough test cases, and you can be virtually assured that you have no memory errors in your C/C++ code.
However, security is a lot more than buffer overflows... but at least it brings you up to the relative security of Java, with speed to boot.
Open Your Mind. Open Your Source.
Every function should be designed with the assumption that its input is faulty, and should have safe failure modes for every possible value and all possible content. Any unsafe external libraries must be wrapped in handlers which verify the data being passed to them with a similar mindset. Do not EVER presume data will be of a certain form, or that a function will be used a certain way. If sequential routines are becoming long such that you cannot verify the accurate function or the absence of a buffer overflow immediately in your head, then stop and look for a way to break it down into smaller abstract pieces.
Combine this mentality with the usage of safe classes as datatypes whenever possible, so that you can wrap your input verification into the functionality of the classes. If prudent, wrap external library routines in classes which manage the interaction with them, and which verify the data content being passed.
Use test suites to test every component of your program, and be sure to include invalid and pathologically insane input in your test suites.
Do not trade security for efficiency. And don't forget to cross your fingers.
The mostly STL gets rid of the old problems such as buffer overflows but introduces new ones that can a lot more subtle and harder to track down such as deep/shallow copy issues. Personally (and I'm probably in the minority) I prefer to deal with the old fashioned bugs since you can usually guess where they're happening whereas in a highly abstracted C++ program using the STL with lots of objects being copied and references flying around it can be a LOT harder to figure out whats really going on , especially since different compilers do different things under the hood.
Change your perspective on the issue. The "insecurities" are a result from what the programmer has written. Rather than viewing them as branches of execution that should not happen, view them as unintended parts of the program that do happen. If you do not want your program to behave that way, then do not write your code that way.
Think about the code as you are writing it. Think about every possible outcome of executing the code you have programmed.
I know the last two are difficult with the hustle and bustle we live in now, but I don't know of a less time consuming solution.
Unless you can account for every instruction in your code, you do not know that your code is secure,
Good luck.
"How do you go about making sure your code is secure? Especially if you have to write in a language like C or C++?" Don't write in C or C++. Duh. Where is it written that all software must be written in C or C++? Is anyone capable of independent thought? There are plenty of fine languages that are safe. Ada comes to mind. Maybe others will come to your mind (if you have one).
How about not using languages that allow buffer overflows?
I let my code have evident, gaping security flaws and make them well known. This way people will never use it in situations where security matters.
regards,
The author of sendmail
I think for some people, moving from using a language like Java to using C can cause them a multitude of problems since there's no bounds checking by default and overruns aren't caught.
For example, I recently fixed a bug Blob And Conquer to do with Strings, the code was something like this:
char nm[2];
nm[0] = mission[11];
nm[1] = mission[12];
The code then went on to doing a
missionNum = atoi(nm);
Most of the time, this'd work OK because of the way atoi works. Other times though it'd stray off into other memory and pick up a random number and return a three or more digit number instead.
Obviously there's an easy way to fix it.
Summation 2
You would sacrifice the flexibility and usefulness of the STL to get a class of bugs that are old and well-known? Hardly seems like a fair trade-off to me.
How do you validate code for correctness? Well, either you use some cool formal specification language, such as Z, and then spend a great deal of time and effort validating (which is actually very advisable for critical code in, say, device controls for medical equipment) or you use blind luck and "proven" techniques, collectively known as Good Programming Practice.
:)
Traditionally it has been important to "specify and validate" requirements acribically, in the belief that this is was the way to write good code. This is partly true, but that way can quickly turn your process into a dinosaur - stifling change and preventing improvement because of non-compliance with "The Requirements".
You can try "defensive coding", which really treats all messages with great suspicion, messages being an old term for parameters. This is a cool technique, but can lead to slower code than necessary, and can lead to some bug being buried if code attempts to heuristically correct for "bad" messages (there is rarely any way to formally specify what is "bad"). You can use LINT tools (and there are very many, very sophistacted tools) which will catch a whole lot of stuff before it leaves the developer's screen. You can try practices such as pair programming and independent code inspection. On the coding side, you can even try (gasp) such methods as test driven development and contract based development.
On the testing side, there is nothing quite like having an experienced, qualified, motivated and _empowered_ testing team. A testing team which knows how to find bugs, knows how to communicate with coders and has the power to step defects going in to production. A technique I particularly like is defect insertion - secretly insert 10 bugs into the code base and see how many get squashed, this will give you an estmate of how many defects your process doesn't find. There are other cool techniques too, some based on mathematical analysis of the code's attribute - the more complex the code the costlier it is to maintain.
Opening up the codebase to many people might well increase the chance that someone will find the line which causes an error - but IMHO no one goes around looking for bugs unless they are looking for weaknesses. And there we have another (unethical) method - pay some hacker doodz to 'sploit your code. Hopefully they will not find a higher bidder LOL.
All of these methods are likely to increase development effort and cost, decrease the number of defects, increase user satisfaction, decrease maintainance costs and increase well-being and harmony. So it is a trade off, perfect code is incredibly difficult to create - the question is what level of perfection are you (and your customers) willing to pay for. Problems mostly arise when expectation does not meet reality - some flakiness in an F/oss application suite is more acceptable to me than random crashes in software which cost me hundreds - or tens of thousands - or millions - of dollars.
In order to increase some quality aspect of code (security, performance, robustness, correctness...) one can therefore focus on one or several categories - the people, the process, the culture, the tools, the technique, the time&cost etc. The choice of what to focus on is dictated by reality: no one has unlimited resources (except, almost, Google).
There is no silver bullet - but there are golden rules. Finding people who know the difference is crucial I believe.
(Full disclosure: Yeah, I'm looking for heavy duty PM work
They who would give up an essential liberty for temporary security, deserve neither liberty or security - Ben Franklin
4) passing strings (or ANY data, for that matter) between separately-compiled, out-of-process components of your program ONLY via safe IPC marshalling mechanisms (like streams, files, pipes, etc...); keep in mind that the STL already has a mature marshalling-to-ASCII/UNICODE mechanism in
It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
Never touch an Irish man's Guinness!@#
How do you go about making sure your code is secure?
In my opinion the unique way is by trying to exploit/crash you program during development using logical and/or fuzzing techniques. Many programmers think that "security" is the last step they need to follow when writting a piece of software but they missed that security is one of the "intermediate" steps, not the last.
In my case, I always conduct an audit in my software when a module (in example) is finished, when I added a new functionality, etc...
In this case it doesn't in one important way. Programming is the same regardless of language, since humans are the same regardless of language. What you need to write good software (again, why just secure? Why focus on a certain aspect, why not just generalize?) is skills/knowledge and good habits. My best advice here is to make sure you give yourself good coding habits. Don't say things like "I'll clean that up later" or "I will add error checks later" or something equally damaging. Give yourself good, sensible, habits and follow them. Any average programmer must know what buffer overflow means, and how to correct it. You can't even be an average programmer unless you know. So why is such insecure code written in C/C++ then? My thinking is plain mistakes and bad habits.
Developers can chose their employer.
You don't know your code is secure. You just know that it handles certain test cases apparently correct.
(Ok... Silly examples like "while(TRUE);" are partially correct, because they never terminate, and thus you can't tell they handle the test cases incorrectly.)
It's like scientific theories. You will never know if a scientific theory is entirely correct. You just can point to the test cases you have thrown at the theory which it was able to handle, and to the results you got from using the theory. It still doesn't prove that the theory is correct, only that you were unable to poke holes in it until now.
So all you can do is check for known traps, border cases, predictable error conditions, and in general following the KISS principle to keep the number of test cases down. And keep all documentations for tests and checks you were doing as long as you are supporting the code.
Not necessarily , all I'm saying is that the STL can introduce bugs of its own that can be a lot harder to find than old style buffer overruns so its not a solution that will get rid of obscure coding (as opposed to logic) bugs.
If you program using strictly functional programming, you can not only verify that your code is 100% secure, but you can even automate the process. (Preferably in a functional programming language such as Scheme, caml, Haskel, LISP, or Erlang; imperative languages make it very difficult/slow to do with functions what functional languages do very naturally and easily.) Purely functional code can be subjected to automated code auditing easily, whereas code auditing imperative code cannot be guaranteed to catch every bug and unintentionally available abuse.
Here's why, and why just about any computational problem can be solved using FP (functional programming):
Functional languages conform to lambda calculus, which has been shown to be Turing equivalent, which means that any program that can be computed on a Turing machine can be solved using Lambda calculus. So long as you program using strictly functions, your program can be verified according to the rules of lambda calculus, and the verification would be as sure as a mathematical proof. This is the only sure way I know of really knowing with mathematical certainty that your application is secure.
Pure functional programming has no assignment statements; there are no state changes for you to keep track of in your program, and in many cases abuses resulting unintended changes of state are the root of security problems. This is not to say that there is no state in functional programming; the state is maintained through function call parameters. (For example, in an imperative programming language, iteration loops keep track of a state variable that guides the running of the loop, whereas a functional program never actually keeps track of state with a variable that changes value; a functional program would carry out iteration by recursion, and the state is simply kept as a parameter passed to each call of the function. No variable with changing state is ever coded.)
Since functional programs lack assignment statements, and assignment statements make up a large fraction of the code in imperative programs, functional programs tend to be a lot shorter for the same problem solved. (I can't give you a hard ratio, but depending on the problem, your code can be up to 90% shorter when described functionally.) Shorter code is easier to debug, which helps in securing code. The reason functional code is so much shorter is that functional programing describes the problem in terms of functions and composition of functions, whereas imperative code describes a step by step solution to the problem. Descriptions of problems in terms of functions tend to be far shorter than algorithmic descriptions of solving them, which is required in imperative code.
Here's the biggest benefit of managing complexity with functional programming: as a coder, you NEVER have to worry about state being messed with. The outcome of each function is always the same so long as the function is called with the same parameters. In imperative programming as done in OOP, you can't depend on that. Unit testing each part doesn't guarantee that your code is bug free and secure because bugs can arise from the interaction of the parts even if every part is tested and passed. In functional programming, however, you never have to deal with that kind of problem because if you test that the range of each function is correct given the proper domain, and pre-screen the parameters being passed to each function to reject any out-of-domain parameters, you can know with certainty where your bugs come from by unit testing each function.
If you need to guarantee the order of evaluation (something that critics of FP advocates sometimes use to dismiss FP advocacy), you can still use FP and benefit: in functional programming, order of evaluation can be enforced using monads. Explaining how is beyond the scope of a mere comment though, but in any case, if you need really reliable code, consider using a functional programming style.
I can't do justice to the matter here; for more information, see th
You can write code that can be as secure as you want, but what about libraries, compilers and hardware?
I think the question itself makes little sense without a deeper investigation in the system!
Intelligence has limits. Stupidity doesn't.
Avoiding buffer overruns should be fairly easy, anyway, shouldn't it? Don't used fixed size buffers, unless you really have a control of what's going in them. And if you do, don't place them on the stack.
...but I agree with previous speakers. Open your source, let the world check it. If you don't, chances are someone will disassemble it and find the flaws anyway, but wont tell you.
Now the *other* security flaws...
just port your proggy to Visual Basic and you'll be fine ;)
But the number of employers where you actually get a chance to use languages like Eiffel, Ada, Dylan, ... is very small.
A monkey is doing the real work for me.
Every function handling alien data should be foulprof. Double check it, let someoneelse double check it. After the incomming data has been verified as correct.. then.. well.. dont care to much, just make sure the logic of the program works. The important thing is after all that no one else can break your program, less important if you can.. If you do you will surely see it in the tests.. But always, always verify all input data the program has. If it doesn't fit what the program exspected, complain and reject or even exit(-1). Never Ever process data in your program you dont have control of.
To summarize, here's how you verify with mathematical certainty that a functional program is secure:
That's the gist of it. Anything more on this topic, such as automatic code auditing with the certainty of mathematical proofs (by means of lambda calculus proofs) is beyond my expertise. I just know that it's possible to truly secure functional code with mathematical certainty, whereas with imperative code, you can only be sure that your code has not yet failed or exposed a rare bug or failure condition.
Yes, sure, if you use STL, you need not worry about getting the buffer size wrong. And that's about it - container indexing is not bound-checked (unless you use at() instead of operator[] - and that's about the only instance of run-time safety check I remember seeing in STL!), iterators can go outside their container without notice, or can suddenly become invalid depending on what their container is and what was done to it. Even leaving library issues aside, there are some nasty things about the language itself - it's just way too easy to get an uninitialized variable or a class member, or to mess up with the order of field initializers in constructor.
This is not to say that C++ is not a good language. All of the above are features in a sense they are there for a reason - but they certainly don't make writing secure software easier.
a) good coding practices
b) formal peer reviews for pre-design, design, code, test specifications, and test results
c) Purify!!! http://www-306.ibm.com/software/awdtools/purify/ A license for every developer AND tester!
I haven't written any code since 1999, but that was how I setup the development team for that company. The reviews also are a form of cross training and team building. Nobody is perfect and showing our individual errors helps everyone fit in. OTOH, there was 1 guy who clearly didn't understand header files and was labled "Mr. Header" for almost a year. After the first 1 week of taunts by his peers, he quickly learned when and how to avoid putting too many header files into his code.
Other code issues were discovered and learned by the entire team. We didn't hide errors, we published them within the team and never told management anything about who caused what to happen.
We all know the answer if we've studied computer science. The problem is that the answer is boring, lots of work and totally non-hip.
It's specifications, pre- and post-conditions, all that "theoretical bullshit" we learned in university. It's just that writing code that way is very un-exciting, and that's a vast understatement.
Assorted stuff I do sometimes: Lemuria.org
Helped a lot for this kind of thing. The tool went downhill quite
a long way but its still useful. Electric fence helps too.
Then a lot of old fashioned software engineering.. use raw arrays
as little as possible, add bounds checking to std::vector [] if you
feel inclined, use gprof to identify any code not being excercised
by your unit tests [you do have unit tests, right]. Lastly, actually
read the darn code and make sure anytime you are using raw arrays
you check the size.
http://rareformnewmedia.com/
Make it part of the critical path in music DRM. Then you know it's not secure.
Not sure about the flip-side, though.
Which is a good thing, Ada was awful to learn and worse to debug. I've seen the light, no more c++ spending hours to decode meglomaniac's tempalates , no more java exception hell , bye bye vb6 error unhandling . Hello C#
...you can ship it.
It's that simple!
How about user/password management ? No matter how your shiny GC collects the garbage you create on memory... You still have the opportunity to make a mess out of faulty authentication schemes or stupid array usage... Besides even though your code is secure, the environment on which it runs may be configured/set up/run by a stupid administrator with all those bullshit certificates in his back. Does it sound familiar ??
All the above statements on the power and elegance of FP are true, but totally unrelated to how programs are actually cracked.
The essence of cracking an application today is to break the semantics of the computational model. Once the attacker breaks that, end of story. This is the common denominator of buffer overflows, memory allocation exploits, TOCTTOU attacks, etc.
Who needs security? Thanks to the DMCA, all I have to do is keep my code proprietary. Then it's illegal for people to hax my code, so it won't happen!
Slashdot Burying Stories About Slashdot Media Owned
For high-integrity stuff, we use SPARK (http://www.sparkada.com/) - a design-by-contract subset of Ada95 that is entirely designed-from-scratch for verification purposes. :-) )
The verification system implements Hoare-logic and is supported by a theorem prover. Buffer Overflow is only one of many basic correctness properties that can be verified. Properties that can be verified are only limited to what can be expressed as an assertion in first-order logic.
SPARK is a small language (compared to C++ or Java...) but the depth and soundness of verification is unmatched by anything like FindBugs, SPLINT, ESC/Java or any of the other tools for the "popular" languages.
(If you don't know or care what soundness is in the context of static analysis, then you've probably missed the point of this post...
- Rod Chapman, Praxis
"Code writting is not pizza baking."
Reminds me of the time when "someone" hacked our new fangled photocopier to complain it was "out of pizza" rather than paper.
And did you exchange a walk on part in the war for a lead role in a cage? - Pink Floyd.
Marucs Ranum notes taht...
I'm not one to orthography-Nazi up a place, but how are we going to fool the noobs into thinking we're better than them with editors overlooking such blatant typos as the above?
Please stop stalking me, bro.
You may be on to something here. Once your box is a pile of smoking rubble from all that trashing, *nobody* will be able to pwn it.
Indeed!
Secure Code is not just about the microcosm of a "routine" or "method", but rather of the entire ecosystem of a collection of code. Don't just look at the security problem through a straw, looking for buffer overflows and the like. You need to find those too, but that's just the tip of the iceberg.
But let's not forget that when an iterator "go outside their container" you already have a serious logic error. The same logic error can be even more catastrophic in other languages that do run-time checking to avoid crashing, and allow you to do something like "on error resume next". BTW, you are allowed to derivate from standard containers and create checked operations (like operator[] that maps to at()).
Other languages have novel approaches to solve C++ problems, but nothing can stop logic errors, wrong algorithms, bad programmers, etc.
As another post pointed out, we all know the answer... Testing and writing code according the best practices documented by so many books. For commercially developed software "code security" is something that is usually addressed based on the perceived risk of a vulnerability. Risk can be quantified by the probability of an event multiplied by danger the event poses. In a commercially developed piece of software schedule and cost drive a program so the developers know the code is not secure and the managers use risk analysis to find the "biggest" holes. Usually too much time is spent in development before testing is considered so you end up with a "lets fix the major problems and ship it". No code is totally secure, but if you demand secure code, you better deploy lots of automated unit/white box or black box tests to mitigate the risk.
today is spelling optional day.
C and C++ coders have jammed allocated memory on to the stack for years to make it "garbage collected" when the frame pops off the stack. That also opens up the very easy to exploit stack overflows, if you put memory on the stack and then do any unbounded or improperly bounded I/O to it, you're done. The STL provides smart pointers to allow you to manage heap as if it were on the stack but the problem remains that you have to manage it.
The word on the street, and I discount it, by a lot of the hackery types is that the use of C++ with any overflow is easier to exploit than a normal C application because it has the virtual function look up table which basically provides an easy one-stop shop where you can get a pointer to almost any other subroutine in the program. It makes sense logically but I don't know of any exploits that make use of it
And automobiles can introduce problems (air pollution) that didn't previously exist with the form of transportation they replaced. But I think we all agree that a little bit of air pollution is better than thousands of people a day being trampled by horses in city streets.
Comment of the year
You also have the ability to use a plugin architecture, such as XPCOM, for the binary compatability issues.
Once you go outside of a container, you already have a fatal error and the appropriate response is to crash (albeit gracefully if possible). The problem isn't so much that the program crashes, but rather that the program may consider data outside of bounds as valid memory, thus allowing buffer overflows and undefined behavior to occur.
The difference between pure C/C++ and the STL is that something like strcmp can create a rather subtle sort of buffer overflow error, whereas buffer overflows involving STL containers are generally easier to avoid and detect. For that matter, if you use the STL algorithms library to its full potential, you may find that you hardly ever need to use explicit indexing or iterators other than begin() and end().
- valgrind is very nice, but only reports memory corruption if it really occurs (i.e. you have to trigger the bug first). Not very useful to detect bugs.
- splint doesn't understand the flow of control, thus it needs tons of annotations to work properly. A royal PITA if you work on existing code. Also, it just shifts the problem: how do you now prove that your annotations are correct? Besides, it produces tons of spurious warnings.
- flawfinder, rats, et. al. just grep the code for suspicious functions like strcpy(). They don't understand C/C++, and thus produce warnings even in cases where it's perfectly clear that these functions are used safely.
- some academic projects (like e.g. uno, ccured,
...) look interesting, but usually don't work on nontrivial code
(at least not unless you are part of the development team and know the required wizardry to make them work). Also,
most acedemic project go into limbo as soon as the thesis is written.
I think one of the major problems is that commercial vendors like e.g. Coverity offer free service at least to major open-source projects, thus stifling any initiative to produce open-source counterparts of such tools.If you want flexibility and usefulness, why not skip C++ and go straight to Java or C#?
"[Regarding the 'cloud,'] ownership was what made America different than Russia." -- Woz
TFA: "Especially if you have to write in a language like C or C++?"
Why would you HAVE to use C or C+ or C*+**+++? I don't mean to be a troll, but if you are writing in an inherently insecure language (i.e., any compiled language) you aren't going to get secure code.
OTOH of you write in, say, assembly, you are setting yourself up for the complexity. You have to make sure your buffers won't overflow, as opposed to leaving it to the compiler writers.
As to overflows, if you KNOW your language is prone to overflowed buffers, it seems wise to check for overflows with your own code. After this long, there really is no excuse for buffers that overflow. It isn't hard to check for the length of a string, after all.
If bridge engineers were as lazy as programmers, bridges would be falling down by the hundreds. My 1992 car is full of hundreds of thousands little bitty moving partsand fluids, but as long as I keep clean oil and filters in it, it doesn't break. My last car was an 1988, it lasted until last year. But I have to replace my 2002 Microsoft operating system because it's not secure? Somebody is making a lot of money off of poorly designed and poorly built software. There is no reason why I should have rto replace an OS.
There are reasons for program errors, but no excuses. If your code is shit, it's shit because you wrote shit. Either you're incompetent or lazy. "You can have cheap, secure, or fast. Pick two."
Those bugs aren't harder to track down than "old-style" bugs, in fact I think they're vastly easier to track down than, say, a wild pointer. The difference is that you're less experienced at dealing with the new problems, so they seem harder to you. With time and practice, you'll see through copy/reference errors quickly. In the meantime, a little discipline can cover your lack of experience -- never store raw pointers in collections, always "objects". If you don't want to create copies, then store objects of a smart pointer class. In fact, avoid ever using raw pointers at all. *Always* assign the result of a 'new' operation to a smart pointer (auto_ptr works for a surprisingly large set of cases, but you may have to get a reference counted pointer type or similar for others -- the BOOST library has some good options if you haven't already rolled your own).
If you really run into different behavior with different compilers, then at least one of the compilers is buggy. That does happen, but it's a lot rarer today than it was a few years ago. When you find that situation, wrap the tricky bit behind another abstraction layer and implement compiler-specific workarounds so that your application code can just use the abstraction and get consistent behavior. In most cases, someone else has already done this work for you. Again, look into BOOST.
Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
And thousands of people a day don't get hit by cars in city streets now?
It was an interesting article and I agree with almost everything the author said, but it was also a multipage advertisement for a commercial application directly hitting the target demographic.
That's hard to buy, and Fortify got it free!
separately-compiled in-process string objects _are_, in general, binary-compatible between versions (at least between "contiguous" versions). Or, better putting it, I, in my 15+ years experience with C++, have never found an instance where, for example, a DLL written with SomeCompiler version 8 would not work OK with an executable written with SomeCompiler version 9 WRT std::string or even floats and doubles.
I agree with you that in-process marshalling is (in general, at least) silly.
It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
He's compiling as root :p
I think it's a bad mistake to make your code secure. If you look at sales figures, you see that sales are inversely proportional to security. So customers don't want secure computer software. If they wanted that, they'd buy it. Clearly, what people want is the most insecure software they can get.
I say go with The Market, and write the most insecure software you can. Securing your software will only waste your time and decrease your sales.
Those who do study history are doomed to stand helplessly by while everyone else repeats it.
I think it was Knuth who said, "In theory, theory and practice are the same. In practice, they are not."
In theory, for any nontrivial program, you cannot know absolutely that it is secure. You cannot even know that it will terminate. The Turing showed that there is no algorithm which will decide if a program will halt. Most other problems of program behavior can be reduced to halting. (Just place a call to exit() immediately after the code that outputs the behavior in question.) In general, there is no way to prove that a program has any particular property that can be reduced to a termination property.
The choice of language does not matter, either. Turing used a language that was very primitive, even compared with the simplest assembly languages. But Turing's language is equivalent in computing power to every modern general-purpose programming language. Church's completeness hypothesis is widely accepted as valid, though a proof in the strict sense cannot be written. So, Turing's mathematical proof of the halting theorem is valid for every modern programming language.
There are some programs for which we do know that the program is correct. Such programs are all very small, solve well-defined mathematical problems, and are written in well defined functional programming languages. These proofs depend on very careful, mathematical definitions of the programming language, and of the function to be computed. The programming language is, strictly, an algebra. The proofs simply show that the algebraic formula (the program) transforms the algebraic input to the correct algebraic output. In every case, such proofs are quite difficult and tedious. And, as noted above, they are not possible in the general case.
In practice, we can apply methods that are known as "engineering". That is, we can apply logic, design, inspection, review, and testing to develop some amount of confidence that it will behave as expected. But, engineering methods do not provide certainty. They only provide high confidence. The choice of language and tools have some effect on the ease or difficulty of doing the engineering work, but do not change the boundaries of what is possible.
How do we "know" that a bridge will not fall down. There are no proofs of bridges. There is only engineering. Engineers apply logic, experience, design, inspection, reviews, and tests, so that they can have confidence in the design. The confidence is based on statistics. For a given shape of steel or concrete, we can measure loads that cause the steel to fail, and we can measure the variance in those loads due to the manufacturing tolerances of the material. When we use that shape and material to build the bridge, we can have statistics about how much load the bridge can support without failing. But even with all that engineering, sometimes bridges do fall down. The load measurements are only statistics, not proofs. There is always a confidence interval around every measurement, and the confidence can never be 100 percent.
We can never have absolute proof of any property of any real, nontrivial program. We can have confidence as close to 100 percent as we want, if we spend enough effort on the engineering.
For ever string function, there's an equivalent that will only perform the operation on the first n bytes. If you're working with a C library that's old and doesn't have such a convienece, you can always wrap it with a call that does.
The real problems come into play when you're using a 3rd party library. You can always police your code, but it's hard to police / fix other's code. Open source libraries are great for this in general, but there's not always an open source solution for connecting to proprietary buses, services, etc.
In the end, solutions that require policing are only as good as policing. Policing is designed to only be effective after some atrocity has been committed, and so policing will likely only be effective after the exploit. A much better solution would prevent use of unbounded string functions by not having them defined. Perhaps there's some compiler magic that could be employed, but I doubt such techniques will gain much traction. It's like asking a guild of master carpenters to switch building materials. Once you know the materials and weaknesses, usually it's better to design around the weaknesses than to change materials.
As a pratical real-world example near me, our school system just replace over a million bricks in a nearby school. The reason was that the new-fangled iodized metal bolts were used (way back when) to bind the bricks to the sub wall. Iodized was new and "hot" and it didn't rust, so the wall should have lasted forever. However, it corrordes when exposed to salt water, and the school was close enough to the sea to be exposed to salt water vapor. The problem was discovered when a worker leaned against a brick wall and it toppeled over.
In the end, education will bring the current coders around, but don't expect the problem to go away. There will be many years of people reading antiquated "how to program" books that teach older, less safe, practices. There will be people reentering the marketplace that will have missed the newer techniques. There will be users installing from the copy of winZip (or whatever) that they downloaded in 2000.
Only with time, and a whole lot of paitence, will this problem die. It won't be fixed, it will decline until it's barely noticable.
Don't blame the tools. No matter the language, when you have input from unknown sources (i.e. a network) *never* trust the input.
There is no excuse for using STL. It is crappy, buggy, slow and impossible to debug.
If you need higher abstraction features like that, you are using the wrong language. Try Java or C#
If you think that the flexibility and usefulness provided by C++ is present in Java or C#, then you are only using it as a nicer C.
And that's exactly why so many things are "implementation defined" or "undefined". Many real-world users of C++ demand that, for instance, vector::iterator be a typedef for a raw pointer for efficiency reasons. Other equally-important users would prefer an iterator type that guarantees sensible behavior in the face of real errors. The ISO standard allows for both behaviors by conforming C++ implementations.
There's something attractive about the Java and C# languages having all constructs so well-defined. But both of those languages could afford not to support real hardware. Both target abstract machines and are happy with the results. C++ can afford no such conceit: it thrives in high-performance, customized, and otherwise exotic environments.
It's always a long day... 86400 doesn't fit into a short.
Dynamic linking will also frequently create thunking tables close together, and lots of C code have other function pointer tables in special places anyway. (In a Win32 environment, you have that table for any COM object, it won't matter if you implement it in C, for example.)
The majority of the time, when used as a verb, Affect is right, and when used as a noun, Effect is right. The fact that the guy is trying to effect change in this matter is a good thing.
So remember, 95% of the time, A is for action, E is for everything else.
Programming vs engineering using real life material
- one major difference is that you cannot do destructive test to the actual building material for your project, so you have to settle for statistics to figure out how the untested material would work.
Software on the other hand can be tested to failure. What's the excuse for not testing it?
The problem of simple string boundary problems is solved in plain old C.
Just that people don't use it because they think "ah, only my program will be running this code, so I already know it is fine.
Let's not forget their wonderful documentation! Complete and accurate API documentation is absolutely necessary for writing secure and reliable software. And of course the programmers should actually read the documentation and check all the details of the API calls they are using (return values, etc...)!
Valgrind can detect use of uninitialized memory, as also access to free'd memory, memory leaks and also unmatched free/malloc calls.
e ction#GCC_Stack-Smashing_Protector_.28ProPolice.29 )
You forgot to mention Bruce Peren's electric fence (http://perens.com/FreeSoftware/ElectricFence/), which will crash your program and generate a core dump in case you overflow/underflow (even by 1 byte) a given vector array. For C++ you can think about some variants, like DUMA.
I think that for stack errors, gcc-4.x does provide some extra protection to detect stack smashing, too. (http://en.wikipedia.org/wiki/Stack-smashing_prot
For C++, g++ does provide a quite unique flag: -Weffc. This little baby checks for some of Scott Meyer's rules to write better code (believe, this one catches a lot of subtle bugs).
Also, you can catch another bunch of code bugs with extensive/intensive unit tests. Recently I was involved in writing some nasty encode/decoding code between several charsets (think about GSM, UTF8, UTF16, UCS-2, etc). Even if we are going to support only english and german, we wrote some code to test other languages (chinese and arabic come to mind). It helped us to detect some missing logic on original code and detect some overflows.
OSS/Free software developers does have a good bag of tricks to help develop and test software, I don't think that the situation is so bleak.
"Too many babies using C/C++."
Wrong. Like Babies with knives and guns (from the GP), the problem isn't the babies, it is the parents fault for giving the babies the wrong freaking tools. Don't blame the babies, they don't know any better.
So, the question is, what is the equivalent to plastic guns and knives in the programming world?
Agent K: A *person* is smart. People are dumb, stupid, panicky animals, and you know it.
The worst offender I have found has been the OS X POSIX threading API documentation. This contains a number of very small errors, and if you write your code to the documentation, you will find things breaking in subtle and difficult to track down ways.
I am TheRaven on Soylent News
Software on the other hand can be tested to failure. What's the excuse for not testing it?
I didn't say that you should not test. I said that testing is an engineering method. Testing cannot provide proof of correctness of nontrivial programs. But the reason may not be obvious to some.
If a program accepts N bits of input, testing requires O(2^N) units of effort (time or parallel resource). For small values of N this might be possible. But nontrivial programs usually accept lots of input. Values of N greater than a few hundred quickly lead to intractable numbers of test cases. Most nontrivial programs will accept thousands or millions of bits of input.
What's worse, many programs will accept arbitrarily large amounts of input. Try to imagine the number of possible key/mouse sequences that you could input into your browser, or into your word processor. The number of possible input sequences is countably infinite. The sun will burn out long before they can all be tested.
At most, a vanishingly small fraction of the possible inputs can be tested. If those test inputs are randomly selected from the space of possible inputs, then they may be considered as a statistical sample of the program inputs, and the resulting outputs can be considered as a statistical sample of the outputs. But, at best, you still only have statistical confidence in the results.
If you carefully choose the test cases, you may be able to use logic to gain increased "coverage", but then the population is not randomly selected, and so such methods fail to provide statistical confidence. An error or omission in the test-case selection may completely fail to select some cases that are actually very likely to occur.
As an engineering method, testing can be quite useful. But testing can not provide proof of properties of nontrivial programs.
As a C/C++ developer I am a little offended by the article summary. Certainly C/C++ has a lot of flexibilities that allow bad developers to write bad code. However, many other languages, e.g. Java, allow bad programmers to write code that looks good because of stronger type checking, reduced use of pointers and the like. However, nothing stops a bad developer from writing insecure code in any language. Maybe you don't manage your resources correctly. Maybe you do a bad job of implementing encryption/protected storage. Maybe your authentication scheme is weak, your site is vulnerable to cross-site scripting vulnerabilities, or your session data can be easily spoofed.
Secure code is not a product of language, it's a product of developers who take the time to fully understand the tools that they are using to build the product, including the ins and outs of their language of choice and its key risk elements, and who research risk elements for all other parts of the system.
I have solved those problems completely with my infinitely large computer. It simulates all possible computer programs. Ultimately, writing any program that you desire boils down to a simple linear search. When asked when coding will be done, programmers can no longer use their stock answers "a half hour" or "two weeks". Even that is simplified to the single answer "on average, half of infinity ". Managers love that shit because it looks good on reports.
Fascism trolls keeping me up every night. When I starts a preachin', he HITS ME WITH HIS REICH!
Your comments are valid, but if one is concerned about security, there are a number of steps to take. First, in regard to the STL (well, to be accurate, that part of the library which used to be called the STL), you can test and debug with a 'checked STL' implementation. Such an STL will detect all out of bounds accesses (not just when using 'at'). They can usually check a number of common iterator problems such as using invalidated iterators, an invalid iterator range (such as foreach(a.end(),a.begin()) ), mismatched iterators ( foreach(a.begin(),b.end()), and so on. STLPort provides one such implementation.
As for problems with uninitialized variables and order-of-initializer problems, one should compile with full warnings on. These types of problems are easy for the compiler to catch, and once warned, usually easy for you to fix.
Anthropic principle: We see the universe the way it is because if it were different we would not be here to see it.
Don't write in C or C++ unless you absolutely have to. If you absolutely have to, make decent plans for dealing with the eventual security problems - like write the crap anonymously or using the name of some politician you decided you didn't like ;).
;) ).
;).
There are plenty of other languages where a whole area of C/C++ problems just don't exist. Pick a decent language or two (Please NOT PHP! Forth is not much better than C). It'll still have problems, but at least you'd have a lot less "common programmer bug = attacker executes _arbitrary_ code of attackers choice" which should be totally unacceptable for modern code.
I personally use perl, and so far none of the bugs found in the programs I write for work would allow an attacker to "execute arbitrary code". It's more likely that any such bugs would likely be a bug in perl or the 3rd party libraries I use (nyah spread the blame
If you don't like perl, you could use python or similar.
Perl of course isn't fast (fast enough for a dhcpd[1]). But other languages like LISP, *ML are nowadays about as fast as C.
If you don't like the other fast languages, write the bulk of the stuff in a slow safe language that you like. Then write the performance critical programs in C and try to keep those really small and secure.
[1] Why a dhcpd in perl? We needed a fair number of features not in the isc-dhcpd and other dhcp servers. And go look at the source code of isc-dhcpd and a few other dhcp servers written in C sometime... Let me know what you think of the code
Why not Python? Existing Python libs don't allow us to make a dhcpd that does what we need.
I suggest you take a look at the smoke from a forest fire started by a spark from a steam locomotive. Then take a whiff of a town where every street is a foot deep in horse manure. Then come back and try to convince us that cars cause more pollution than their predecessors.
Lack of pollution in the past is almost entirely a fantasy. Especially during the early industrial revolution, many cities (especially industrial centers) had air pollution so bad that they typically ran their street lights 24 hours a day.
The universe is a figment of its own imagination.
They may not be complete solutions, but a few practices avoid a lot of problems:
Visual Studio 8 examines the use of the C run time library and will warn about security concerns. For example, the compiler will complain about 'strcpy' suggesting using the secure version. You must add a #define to disable this new feature if you want your existing code to compile.
Also, the C/C++ journal is an excellent resource for writing good secure C/C++ code. There was an artical a few years back that demonstrated using stl:vector:pointer as parameters to CRT and Win32 API functions which add a layer of security.
I didn't say they produced more pollution. Well, maybe I did, but I meant they introduced new problems that weren't problems before, but in every other way were better than the alternative. Excuse me for momentarily forgetting how pedantic Slashdot posters are that they would ignore the POINT of a post to nitpick some detail.
Similarly, C++'s STL may introduce new problems, but it sure as hell fixes a metric ton of them in the process.
Comment of the year
I'm not sure what makes you think "any compiled language" is inherently insecure, but I'm pretty sure anything that would support such a claim would apply equally well to assembly language. An assembler is enough like a compiler that almost any characteristic inherent to one is virtually certain to be inherent to the other.
An utterly nonsensical comparison. The 2002 code does exactly what it did back then, just as well as it did back then. It won't ever wear out in the way your car did.
If you insist on comparing a a computer to a vehicle, compare it to something like a tank or a jet fighter. It's a target in a hostile environment (i.e. a network), surrounded by enemies ready to exploit any weakness they can find.
I suppose you also think the designers of WW I biplanes were lazy because they produced something that couldn't compete with an F15?
Even the greatest chess masters lose occasionally -- and compared to programming, chess has simple rules, a well-defined goal, a stable environment, etc.
The universe is a figment of its own imagination.
If you're writing C code and you're not wrapping your memory allocations/deallocations in a more fortified layer than malloc, you're asking for trouble. It's possible to do much more robust memory management and memory integrity checking if you do this. It's not foolproof, like many suggestions, but it can really help.
There was a time when movies had plots. So you knew who's ass it was, and why it was farting.
-Not Sure
Oh, and if you find anyone who's actually writing software that way, let me know, I may want a job there.
- "History shows again and again how nature points out the folly of men" -- Blue Oyster Cult, 'Godzilla'
Or to put it another way, it says there exist programs for which you cannot prove whether they halt. But it does not say that all programs have that property, only that there must exist at least one.
- "History shows again and again how nature points out the folly of men" -- Blue Oyster Cult, 'Godzilla'
I don't understand why people continually compare programming with building bridges, or cars. .... Until the same care is taken designing software as it is to design bridges, they can't be compared. .....
So if we don't compare programming to engineering, how exactly will we GET that level of care?
We SHOULD make the comparison, because software is just as vital to our economy as those other things, yet we don't demand it, we aren't willing to pay, vendors won't deliver, and government doesn't regulate it.
The first step is realizing that, yes, it is possible to write software with a lower number of defects, and no, Johnny the philosophy major who picked up a book on Ajax is probably NOT going to be part of the team that delivers that secure web app.
Write an input routine that cannot be overflowed; takes it's characters one at a time, counts them, makes sure each byte is counted if they're multibyte, stops before filling the return buffer and positively terminates said buffer, obeys length restrictions from the caller which are REQUIRED in order for the routine to work in the first place, and preferably enforces some kind of sanity on the data itself (I want an int... a float... a double... ASCII... Unicode... a complex number... a url... etc.)
Direct everything that takes data through this bottleneck. If you come up with a need for a new datatype, write it into the bottleneck. Don't write some new chunk that has to be maintained separately.
Your program should never be exposed to a string it doesn't like, can't handle, or contains anything that doesn't look like exactly what you asked for.
A similar approach is called for with regard to memory when using C. You should never let the OS manage memory using basic memory allocation controls. Provide, and mark boundaries on your memory. Track your use 100%. Check those boundaries for violations when the memory is being deallocated and at other times that seem prudent to you. At exit, call a general deallocator to clean up anything that is left over and scream bloody murder about if anything is found still allocated, and about any bounds that are written over. The time taken to write a fast memory allocator that watches for border excursions will be returned many times over in applications that don't leak, don't break and don't annoy your customers (or yourself.) You can, if you like, write this two ways: One for testing, where everything is turned on and will hair trigger, and one for release, where most of this stuff is off for speed... but frankly, you should keep everything on all the time, because your code should never screw up AND because a good reporting section will let you find a bug in about two seconds. And besides, it'll teach you to write fast memory allocation and testing code.
Write a powerful linked list system. Aside from the fact that it's a great exercise, it has tons of uses for memory management and again, will pay for the time taken many times over. These are typically very small in terms of the code required for all manner of sophisticated and cool list handling functions, as is a memory manager. Input validation isn't that simple, or at least, not as you add significant numbers of well checked datatypes, but it is so useful that even if it does take a hundred k of code (it won't, I'm exaggerating) it's still worth it.
One last thing: Don't use other people's code if they've buried input routines in it. Yes, that means that many objects are out of bounds. Tough. Man (or lady) up and write it yourself. If you don't know exactly what is in there, and you can't vouch that it is 100% safe, you have no business using it anyway.
I've fallen off your lawn, and I can't get up.
Other than the minor detail of using the term "STL", I agree completely. Actually, I'm a bit surprised that nobody mentioned the problem that I think is most annoying: the fact that a truly trivial error can result in an error message that's three pages long and nearly impossible to decipher. Leor Zolman's stlfilt can help, but it's hardly a panacea. (And yes, if there are any other old farts like me reading, this is the same Leor Zolman who wrote BDS C, back before the continents separated and such...)
In case anybody cares: I object to "STL" on the grounds that it's extremely ambiguous -- some people use it to refer to the entire STandard Library, others to refer to a library written years ago by Alex Stepanov, still others to a library currently maintained by SGI based on Alex Stepanov's library, and still others to those portions of the current C++ standard library closely based on Alex Stepanov's library (usually with a rather poorly defined boundary). Still others seem to use the term to refer to all code that uses templates. While ambiguity in English is hardly new or unique, this situation seems worse than usual to me -- enough to warrant avoiding the term altogether.
The universe is a figment of its own imagination.
STL doesn't introduce bugs, you do. Never place objects which don't meet the minimum requirements for being placed in STL containers into STL containers, and you'll be fine. (If we're talking buffer overruns, aren't we talking about strings and std::vector, anyway?)
FUD alert!!!
o rmick.html
C# might be appropriate for your domain but it certainly isn't in Ada's - safety critical or mission critical systems.
It's also easy to learn as can be seen here http://www.stsc.hill.af.mil/crosstalk/2000/08/mcc
I wrote a buffer memory manager library with a well defined interface in C that had no buffer overflows in itself. It took me 3 days to implement the code. It took me another 3 days to write the test harness and fix all the bugs it found.
The test harness was written to test every aspect of the design of the library. I ran the test with gcov a gnu code coverage tool to ensure that I exercised very code path. I then put multiple bizarre random values into every function call and made sure that I correctly handled every case, within reason. I tested it until it ran out of memory, to make sure that part worked and it would return appropriate error codes to the higher level system. I did assume that the function putting data into me did know how long their block of data was and that I could read through that block of data without an error. I also handled the case of a NULL pointer being handled correctly in any pointer that was passed to me. It took me another 3 days to write the test harness and fix all the bugs it found.
That code, despite being fairly complex code that ended up getting used in many places in our product to replace buggy slow older code, never caused a single crash. All thanks to a few days of upfront unit testing.
Well defined interfaces that obscure the access to lower level data structures combined with robust unit testing will save so much time and energy down the road.
What I find annoying in C is that there is still no string data type that has a length associated with it as part of the language standard. C uses a string that is NULL terminated, which means that the terminator is part of the data stream. This is an awkward design that makes it impossible to elegantly design anything that can have to handle data with NULLs in it, which is nearly all data. That alone would go far in eliminating most of these overflows. Plus there would be a lot fewer bugs in a standard string type, a lot less than having everyone haphazardly having to design and implement their own string functions in every program written.
If I could pass a string variable into read() then it could return to me the string with the length filled out. strlen() would be deprecated as no longer ever needing to be used.
It is just crazy for everyone to have to invent or find their own version of string libraries to use, considering how much these libraries are used. The same goes for working with IP numbers.
Let's bring the standard C library up to the 21st century!
never store raw pointers in collections, always "objects".
This will kill multithreaded programs. For example, resizing a vector can move it around in the memory, invalidating all pointers to all objects in the vector. Smart pointers might save your day (no experience), but they are not in the C++.
This is one of the cases where C++ loses 10-1 to e.g. Java.
If you really run into different behavior with different compilers, then at least one of the compilers is buggy.
Or your code has a bug which becomes a defect only with some implementation(s), STL allows very different implementations e.g. for string.
In a scenario like that, the objects in the vector should be smart pointers, not the ultimate referents themselves. So, the vector contents can be rearranged without affecting other smart pointers to the same referents.
Smart pointers might save your day (no experience), but they are not in the C++.Yes, they are. If the ones in the standard don't provide the semantics you need, it's usually easy to find some that do. If you can't find any, then you can always create the ones you need.
This is one of the cases where C++ loses 10-1 to e.g. Java.Your premises are faulty, hence your conclusion is faulty.
Or your code has a bug which becomes a defect only with some implementation(s), STL allows very different implementations e.g. for string.Examples?
Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
, especially since different compilers do different things under the hood. Thats an urban legend. Regarding to it can be a LOT harder to figure out whats really going on : certainly not. In C++ the bahaviour is well defined. And if you have troubel to debug a C++ programm and you assume copies (shallow or not deep enough etc.) or references are the problem, then set a break point in the constructor.
If that does not help, then check for the methods that might get "synthesized" and if they are not defined, then define them!
angel'o'sphere
Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
In the old days, we didn't trust anyone else to handle our memory. We did it ourselves. Heck, I didn't trust smart pointers either.
Either you know how to manage memory or you should be writing in a scripted language, not C/C++. Go back to PHP or Python if you must - or worse, Java where 95% of the programmers don't have clue about the OS they are running on. It really is quite sad.
I'll continue to manage my memory myself, thank you very much.
There is no security, if you are willing to assume sufficient lvl of attack.
If you use a compiler, the compiler can insert code into your executable. One of the K&R guys did that to see how long it would go before being noticed.
If you write your own compiler by handcoding in assembly, the chips themselves can do things they aren't supposed to.
If you make your own chips, the silicon can be infected by nanomachines designed to etch extra pathways into your chips.
Nevermind the fact that to design your own computer, you need advanced and therefore possibly compromised software. And you need an OS, which it's doubtful you can write your own (if you are skilled enough to both design your own computer and write your own OS, I salute you!), so thats another possible problem.
And even if you make the perfectly secure system, starting from grains of sand you gather yourself, the second its out of your sight, it could be altered.
Now, I admit, all of the above is fairly paranoid. There's very little reason for anyone to go to the extremes needed to embed compromising hacks at the chip or OS level. But there is no absolute security...
Hmm. Would you call Java, Haskell, OCaml, or Common Lisp "inherently insecure languages"?
Follow that advice if you want a horribly leaky app. As a bonus, adding threads will give you crashes left and right. Cleaning up the mess is extremely labor-intensive and difficult for even the most skilled developers.
Boost is a pig. Pigs can fly, if you supply enough thrust. Rocket scientists are not cheap, and probably the pig will die anyway.
Better advice:
Stay far far away from boost. Always clearly document your object ownership and locking rules. Write your code to be simple, basic, non-nonsense, simple, clear, and simple. Debugging is harder than writing the code in the first place, so if you write the most clever code you can, you will not be able to fix all the bugs. Worship the KISS principle.
Implicit in all of this is the use of a relatively small range of materials with well defined properties. Software is made out of ... bits. No material properties, thus very hard to predict its behavior.
Parity: What to do when the weekend comes.
What happens when I need higher abstraction features like those of the C++ standard library, and I am developing for an existing hardware platform and operating system that has a C++ compiler but not a Java or MSIL virtual machine?
Developers cannot choose where their parents raise them. Or is it usual for a person who has never been employed before to relocate internationally to find work?
Either way, the thing is, STL has direct equivalents to both, with the same quirks - namely, lexicographical_compare (okay, so it requires end of sequence to be defined explicitly, and is thus more akin to strncmp) and copy. Both can go out of bounds, the latter particularly easily since it does not even know the end of one of the sequences. Then there's insert_iterator and friends - all the same problems there.
So, no, relying on STL algorithms won't make things much better. C++ is still C++, and you still have to be very careful to avoid accidentially pointing the gun at your foot.
Of course, as another reply to my post mentioned, one can (and should) use a checked-iterator STL implementation for debugging. But such things exist for C as well.
Patient: It hurts when I do this.... ouch!
Physician: Don't do that then.
Patient: If I don't do this, then my boss will stop giving me paychecks, and I can't buy food anymore.
Now what does the physician say?
The real problem was the widespread decision to use low-spec battery-powered devices, which can last long on a charge precisely because they are underpowered, as if they were suitable for general purpose computing.
Or on computing devices that are extremely limited in the amount of current they can draw. Think of microcontrollers.
Is the Ada standard library ported to my target platform (which is not Windows nor Mac nor POSIX)?
baz = malloc(strlen(foo) + strlen(bar));
sprintf(baz, "%s%s", foo, bar);
if you could write
(string-append foo bar)
etc.
Because your development kit provided by the platform vendor comes with a C environment and not a Lisp environment.
How many states are in your ThinkPad, and for how many machine cycles has the universe existed?
In FP, as far as I remember, nobody does their own memory allocation, so memory allocation exploits would not be attacking your program, but the implementation of the FP system you're using. If your computational model is purely functional, memory allocation exploits would be pretty much impossible, as far as I understand.
I don't know if this is true in general, but as for buffer overflows, at least in Scheme and Lisp, if you handle input using lists, or even circular or recursive lists (as opposed to arrays that can be overflowed), it is impossible to overflow a buffer to attack other parts of the computer memory. Then, whatever you're going to input that list to (or circular/recursive list) should simply filter and check the input to make sure it is the right domain for the function handling it.
How about instead of testing IsSecure(), testing HasNoKnownModesOfInsecurity() to sweep for a list of the most common attacks? You can automate that in FP a lot more easily than you can with imperative languages.
I know that at least in Scheme and Lisp, since the syntax is so simple (all the code is just a bunch of nested lists, and nested lists are effectivley trees), code auditing is simply a depth-first-search examination; check each part for known and common attacks.
That's what I mean by automated code auditing. If you can't know that the code itself is totally secure, you can at least know that it contains none of the common known vectors for attacks. This is a lot lower threshold to satisfy than checking for total security, and I suspect in most cases, it is sufficient to defend from all but the most sophisticated attacks.
You seem to be saying that people who purchase software tend to harm the economy by purchasing cheaper, lower-quality software than they should. How in the world did you make that determination? Perhaps most software is made to an appropriate level of quality, with some being better and more expensive than it should be, as well as some being worse and cheaper.
To go another step, if I were to claim that hundreds of millions of dollars were wasted every year making software needlessly good, and this unnecessary dedication to quality was harming the economy, how would you refute that?
Seems the process follows the laws of construction instead, as aggregated below:
:-).
1 - measure with a micrometer
2 - mark with chalk
3 - cut with an axe
4 - if it doesn't fit, use a larger hammer
Insert
You are getting confused between programming languages and foreign languages. Or are there countries so small that only one programming language is in use there?
The first one is that we don't get the max amount of quality out of our dollars. There's a large amount of quality available "for free", as the research (and my experience) shows that it takes as long time to create high quality as low quality software, because there's so much time wasted on debugging etc in the low quality case that the lowered development time does not pay off. Extremely high quality is a different beast, with greatly increased costs.
The second part is that the consumers do not know what quality they buy. Quality is a "negative feature" - consumers tend to assume it is there, and get annoyed when it isn't, and it's hard to acertain before doing a purchase and using the product. To make the market work ideally here, the purchasers should have perfect information. That's of course impossible, yet it's possible we could make things better with some sort of labelling system - if we could make a reasonable one (and that's a non-trivial problem in itself).
Another problem is that having high quality may not be a sales booster *even if the price is the same*. Having low quality means that users invest more emotions in their software as they learn to work around bugs etc, and that they are more afraid of testing other things, as they've had to invest so much in this software (and think they'll have to invest as much in a new type.) This skews the market away from rational self-interest (which would discount investment to present value, as in "don't throw good money after bad") and towards the lower quality variants.
I'm not sure how far from optimal this move the market; quite a bit, I think, but probably not as far as many people think.
Eivind.
Doubting the existence of evolution is like doubting the existence of China: It just shows that you're uninformed.
You're correct; I meant strcpy.
Bravo. Well-said.
[Ducks and runs]
On this topic, how many people here are using talloc() ?
"Nine times out of ten, starting a fire is not the best way to solve the problem." - my wife
Maybe not countries, but there are geographic areas so small that only one kind of application is developed there. For instance, if I have a degree, and I want to gain experience in order to become eventually independent from my parents, and my parents live where the only available programming jobs are for web developers, and I want to develop video games, what should I do? Even in North America, where countries are generally larger than in most of the rest of the developed world, is it usual for somebody who has never been employed to relocate from Indiana to the State of Washington for his or her first job?