
Printable True Bugs Wait Posters - liotier
http://natashenka.ca/posters/
======
TeMPOraL
Pro tip: when you develop with gcc, don't settle for anything less than

    
    
        gcc -ansi -pedantic -Wall
    

At university I often had people coming to me and asking, "my program compiles
correctly, but it keeps crashing / doing weird things; what did I do wrong?".
I always said, "add '-ansi -pedantic -Wall' to the compile flags and come back
to me when you cleared that wall of warnings down to nothing". Every single
time the problem was directly or indirectly caused by the things that were in
the warning messages.

It's a shame that the default choice of GCC flags make this compiler pretty
much useless for work.

The warnings are there to help you. You can choose to ignore them and that's
fine, _as long as you do it deliberately and with a damn good reason_ , not
because you don't even know they're there.

~~~
nitrogen
You can go further and specify a particular standard, plus extra warnings not
included in -Wall:

    
    
        gcc -std=c99 -Wall -Wextra -Werror
    

I'm not sure if -pedantic is still beneficial in that case. The gcc
documentation had a list of every warning category, and which parameters
enable each warning. This SO question was also interesting:
[http://stackoverflow.com/questions/11714827/how-to-turn-
on-l...](http://stackoverflow.com/questions/11714827/how-to-turn-on-literally-
all-of-gccs-warnings)

~~~
sp332
A tiny comparison: -Wall -pedantic gives me:

    
    
      warning: C++ style comments are not allowed in ISO C90
      warning: ISO C90 forbids mixed declarations and code
    

-Wall -Wextra gives me:
    
    
       warning: unused parameter ‘type’
    

For me, -Wextra is much more useful for finding messy code.

~~~
TeMPOraL
Use both of them. The last warning is about messy code, but the first two will
help you keep the code portable.

------
orangeduck
Half the people in this thread seem to have missed the point. This article is
not supporting 100% abstinence of these functions. It is doing exactly the
opposite - and showing up people who say "never do this" or "that is always
wrong" as being as ridiculous as those who blindly support abstinence from
sex. This kind of tunnel vision, learning by rote, and refusal to teach what
is really happening, is exactly the same stupid attitude that creates bad
programmers, as it creates unbalanced teenagers.

Perhaps, just like condoms, memcpy, strcpy, strcat are dangerous or
ineffective 10% of the time. But that other 90% of the time, when used
correctly, they are perfectly safe, fun and essential to learning and growing.
Avoiding them completely does not create a healthy relationship between a
language and its programmer. I realize that not everyone in this thread is a C
programmer, but this prevailing attitude of saying "this should never be
done/used" just because you're heard that from someone else, is a really
petty, annoying, and persistent aspect of programmer culture.

~~~
michaelt
I'm a beginner C programmer, maybe you can share your experience with me.

I've found bugs in libraries where sprintf was used instead of snprintf and it
caused crashes. So I know from experience of cases where snprintf was a better
choice than sprintf. And I've certainly coded a few off-by-one errors in my
time so I can sure understand it's easy to get the destination buffer size
wrong!

I'm not doing anything performance-critical with strings. Under what
circumstances should I use sprintf instead of snprintf and what benefits will
I see?

~~~
orangeduck
If you understand the difference between snprintf and sprintf, what trouble it
can cause, and where to use it, it sounds like you're already doing great.
What would be bad was if you had the blind notion that "snprintf is good" and
"sprintf is bad" without knowing why.

As for an example of when you might want to use sprintf. If you compile to C89
(ANSI) snprintf isn't included in the standard so you're left with sprintf if
you want your code to be portable.

A better example is strcpy though. A function which is completely normal and
safe when used correctly, but someone with the wrong idea might use strncpy as
a "safer" version and cause themselves more trouble for not knowing what is
going on. As if to prove my point you can see someone advocating this exact
thing in another comment tree in this thread. They've probably heard from
someone that the "n" version of functions are safe. If they'd actually looked
into it they'd realize strncpy doesn't do what you might think.

------
raverbashing
Or even better, don't use C for string handling.

It's too much trouble for too little gain.

I think the areas where C is a good and effective solution are shrinking and
safer languages are becoming more common and faster (even C++)

The C syntax, not its library doesn't allow for good string handling. String
handling should be built deeper into the language, and, yes, even though it is
possible to have safe C code, it's _very hard_. So try when it's worth it.

~~~
peterwwillis
> safer languages are becoming more common and faster

> though it is possible to have safe C code, it's very hard

A dull knife is pretty safe for most people. It's still possible to shove it
into your eye and blind yourself, but other than those extreme cases it won't
cause much injury when used in the regular manner. However, it is also
extremely inefficient at the purpose it was designed for: cutting things.

There are, of course, safer alternatives to a knife. EMTs use special tools
designed to fit a seatbelt or cloth into a small slot and slice through
without any risk to a person; they also have specially designed shears which
make it difficult to cut flesh, but easily cut through nylon and leather.
Utility knives have retractable blades to reduce injury, and other tools are
designed to fit specific materials into slots and make cutting people
impossible.

All of those are purpose-driven and application-specific solutions, however.
For the most high performance and general purpose application, a really sharp
fixed-blade knife is still the most precise and efficient tool for the job.
When wielded correctly it is still safe and efficient. But the practitioner is
not protected from harming themselves; it's expected that they know what
they're doing. And really, it's not that hard to learn how to use it
correctly.

But I totally get that it's easier to use a dull knife or scissors than learn
all about knives, and it gets the job done.

~~~
WildUtah
"A dull knife is pretty safe for most people."

While your point is true, I want to object to your metaphor. I object for
safety purposes. In fact, a dull knife is more dangerous than a sharp knife
for most anyone who needs to cut things.

You need to press much harder with a dull knife and sometimes even to saw down
into the object. You may even need to get a firmer grip on the object you're
cutting to counter all that force. Those are very dangerous behaviors. A sharp
knife that cuts easily is much, much safer.

~~~
peterwwillis
Not true. A dull knife is dull; it's not dangerous at all because it basically
can't cut anything. A half-dull or half-sharp knife is dangerous. It can cut,
but you don't know how much, and variations in the blade make it
unpredictable, in addition to the behaviors you defined.

~~~
dllthomas
I would describe a typical kitchen table knife as a "dull knife", and trying
to use that for tasks to which it is not suited can certainly lead to injury.

------
skywhopper
Obviously strcpy is dangerous, that's why I copy all my strings by hand with:

    
    
      while(*dest++ = *src++);

~~~
delinka
I really hope this was sarcasm. But if not...

There's nothing here to prevent a buffer overrun. If your src doesn't end in
0, or your dest is too small, you'll be reading memory you shouldn't and/or
obliterating memory past your dest buffer. Your method is pretty much on par
with an inlined strcpy.

~~~
tiziano88
That's the joke

------
dmm
Develop your c code in OpenBSD. The linker admonishes you any time you use
unsafe string functions.

    
    
         warning: strcpy() is almost always misused, please use strlcpy()

~~~
groovy2shoes
By default, Microsoft's C compiler will also give you warnings for unsafe
functions. At least, it did the last time I used it a few years ago.

~~~
ygra
It still does. Microsoft also banned a lot of C functions from usage
internally [1]. For codebases that need to build in VC and other compilers I'm
not yet sure how to really solve this apart from _CRT_SECURE_NO_WARNINGS.

[1]:
[http://msdn.microsoft.com/library/bb288454.aspx](http://msdn.microsoft.com/library/bb288454.aspx)

~~~
anon4
How about just taking BSD's functions and using them? strlcpy, strlcat,
snprintf, etc. are all easily portable and libraries probably already exist
for MS's compiler.

------
lowmagnet
(Not a C person here, but I'll ask anyway)

What should I use instead of these things if they're so dangerous?

~~~
danielweber
Almost every one has a _n_ version you should use, and their man pages will
tell you that.

strcpy -> strncpy (or strlcpy on BSD)

strcat -> strncat (or strlcat on BSD)

sprintf -> snprintf (but still watch out for printf format attacks)

gets -> something else entirely. The man page says "programs should _NEVER_
use gets()".

~~~
ledbettj
Keeping in mind that strncpy has it's own problems, like not null terminating
the buffer if it would overflow.

~~~
santosha
The point of the n is that you specify the maximum length that it's allowed to
copy. It's slightly harder to mess that up than with regular strcpy.

~~~
tobiasu
The n in strncpy describes to what size the destination buffer (not string)
should be padded with '\0'.

This is useful for copying a string into a fixed size buffer that is sent over
the network, to give an example. It's not what the programmer generally means
when using strncpy.

Many programmers are surprised when they learn that strncpy() really writes
1M-strlen("abc") zeros in the 1M char array every time it's called...

~~~
dllthomas
_" The n in strncpy describes to what size the destination buffer (not string)
should be padded with '\0'."_

This is false.

From the man page: "The strncpy() function is similar, except that at most n
bytes of src are copied. Warning: If there is no null byte among the first n
bytes of src, the string placed in dest will not be null-terminated."

And the following code prints foo:ar on my system.

    
    
        char buffer[10];
        strcpy(buffer, "foobar");
        strcpy(buffer, "foo");
        printf("%s:%s\n", buffer, buffer+4);
    

Edited to add: huh, scratch that. Obvious error in above test :-P. Testing it
with str _n_ cat like I had meant to, it seems it is in _fact_ padded, not
just (possibly) terminated. Interesting, and very worth knowing if you are
trying to move a probably small string to a large buffer under time pressure.

~~~
tobiasu
What is false? I'm not talking about the source string not being terminated
when it's too long. That's obvious and there are plenty posts about it in this
thread.

Not sure what you want to say with the example code. Maybe swap it for strncpy
and strlcpy and see whether that matches your expectations?

~~~
dllthomas
Yeah, my bad, had meant to use strncpy. My contention had been that it only
zeroes the first following character (if that). On closer reading of the man
page, it is in fact clear.

------
jere
If you don't write C very often (I don't) and you want to see these things in
action: [https://microcorruption.com](https://microcorruption.com)

I had no clue printf was problematic.

~~~
meowface
printf (and others in that family of functions) are only exploitable if you do
something like `printf(user_controlled_str)` (possibly with extra arguments).

Basically, don't let the user control the very first argument (which would
allow them to add format specifiers like %d or %x) and you're safe.

~~~
jere
Well, yea. This is exactly what you do in a few levels of microcorruption.

You can always say "dont do X and you'll be fine." But that's kind of like
saying "don't point a gun at someone" and the gun will be completely harmless.
That's the trick, isn' it? That seems to be the point of the "True bugs wait"
site at least. It only takes one mistake.

~~~
meowface
I agree, especially with things like strcpy and strcat, but printf is kind of
a special case because it's a very, very simple rule to follow. Plus most of
the time it's illogical to use it without a format specifier (or with user
supplied ones).

------
yetanotherphd
Even though I don't think abstinence-only sex education is a good idea, it's
strange that the true statement "only abstinence is 100% effective" is mocked.

Or are liberals going to start teaching an honest version of their view: "A
combination of condom use and abortion when condoms fail, is 100% effective"?

~~~
gizmo686
I've only sees "only abstinence is 100% effective" mocked from a policy
perspective. It is true that abstinence is 100% effective on a personal level,
but teaching it is remarkably ineffective at a population level. There is room
to mock it on a personal level, by pointing out that we are willing to engage
in far more dangerous activities without 100% guarantees on safety. 'Seatbelts
fail, only not driving is 100% effective'.

~~~
yetanotherphd
>I've only sees "only abstinence is 100% effective" mocked from a policy
perspective. It is true that abstinence is 100% effective on a personal level,
but teaching it is remarkably ineffective at a population level.

The phrase "only abstinence is 100% effective" is a slogan for teens, not a
claim that only abstinence only sex education is 100% effective (which is
clearly false).

>There is room to mock it on a personal level, by pointing out that we are
willing to engage in far more dangerous activities without 100% guarantees on
safety. 'Seatbelts fail, only not driving is 100% effective'.

It depends on how much a person wants to avoid having an abortion or unplanned
pregnancy, and how much value they get out of sex.

~~~
jjoonathan
> The phrase "only abstinence is 100% effective" is a slogan for teens, not a
> claim that only abstinence only sex education is 100% effective

You don't have to claim that a stupid course of action is perfect to deserve
mockery. Following the stupid course of action will suffice.

> It depends on how much a person...

No, the success of abstincence-only education as public policy does not depend
on a single person's wants, desires, and incentives. It depends on the wants,
desires, and incentives of an existing imperfect population.

Claiming that "our policy would work if only people were moral and rational in
X, Y, and Z ways" is irrelevant if people are known to not be moral and
rational in X, Y, and Z ways, which is indeed the case with respect to sex-ed.
At the end of the day it either works to reduce teen pregnancy or it doesn't,
and in this sense abstinence-only education doesn't work.

------
infruset
What are those ads referring to originally? Is this a campaign in the US? Is
it publicly funded?

~~~
Nursie
Sexual abstinence. And yes IIRC they are publicly funded in some states.
Worse, they either don't give accurate information about contraception or give
no information at all.

Needless to say, these policies have proven to be counterproductive when it
comes to actual teen pregnancy and STI rates.

~~~
Bluestrike2
Not that the negative correlation between abstinence only programs and
pregnancy + STI rates deters the people who push them. When you start to view
public health policy through the lens of individual morality (if not piety in
some cases), the actual effects of a given policy effectively become
irrelevant next to the intent of the policymakers.

To the unfortunate consequence of many teenagers.

~~~
Nursie
Of course, because if they don't heed your awesome moral advice and get into
trouble then you can blame them for it!

I wish it wasn't so easy to be a misanthrope.

~~~
Bluestrike2
Ugh. That part makes me sickest of all.

------
epx
I would like C to have a native String type, and the primitives could be
function pointers, replaceable in those cases when custom handling is needed
(e.g. inside kernel). Object Pascal is sort like that.

~~~
eric_bullington
D has this. A lot of people assume that D is just C++ with some GC and some
improvements, but it's really more like _C_ with GC and some improvements --
including a native String type.

There's also a string module in the standard library that includes a lot of
convenience methods, including ones for interoperating with C and for working
with Unicode[1].

For someone like me with a background in dynamic languages like Python and
Lua, as well as some background in C, D was a great fit. Unlike when I started
learning C++, D felt like a very natural extension of C to include GC and lots
of modern language features.

Lamentably, not many people are interested in D, and so aren't yet a lot of
third-party libraries, and many of those that are abandoned. But the core
language and standard library are great, and there's a nicely growing and
incredibly fast web framework (vibe.d). And Facebook has started supporting
the language. So hopefully it will start seeing some growth.

1\.
[http://dlang.org/phobos/std_string.html](http://dlang.org/phobos/std_string.html)

------
asgard1024
100% effective? Just wait until your friends invite you to a Hackathon, and
all promises will be broken that night..

------
facepalm
Nice - although I wish they would fix the bugs in those libraries, too.

~~~
danielweber
Many of the man pages for the function say "don't use them." OpenBSD let you
link against "strcpy" but screams at you if you do.

Also, what's pickle? PS: don't type "man pickle" into the google, you won't
like it.

~~~
anonymoushn
Pickle is Python's native object serialization. Unpickling user inputs is
executing arbitrary code.

~~~
pekk
Not accurate, Python has multiple serialization libraries and there is nothing
special about pickle. Python's internal serialization is 'marshal' and
shouldn't be used by apps for other reasons

~~~
dalke
anonymoushn said "object serialization". "marshal" doesn't serialize objects.

    
    
        >>> import marshal, cPickle
        >>> x = object()
        >>> marshal.dumps(x)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: unmarshallable object
        >>> cPickle.dumps(x)
        'ccopy_reg\n_reconstructor\np1\n(c__builtin__\nobject\np2\ng2\nNtRp3\n.'
    

That's a bit tongue-in-cheek, but it shows that the marshal serialization only
handles a handful (I count 9) of built-in object types.

What's "special" about pickle is it's the default recommended serialization
method. Quoting
[http://docs.python.org/2/library/marshal.html](http://docs.python.org/2/library/marshal.html):

> "If you’re serializing and de-serializing Python objects, use the pickle
> module instead – the performance is comparable, version independence is
> guaranteed, and pickle supports a substantially wider range of objects than
> marshal."

------
PaulHoule
Friends don't let friends program in C

~~~
dllthomas
I would punch my friends if they tried to stop me.

------
paulrademacher
True bugs wait in haunted attics.

------
benihana
Not a C guy. Why are these functions unsafe?

~~~
Roboprog
Here, runtime, make some results and put them into this (character array)
buffer I'm providing for you. Oh, the buffer wasn't big enough? Well, I'm sure
the stuff after the buffer's end that you wrote over wasn't all that
important, anyway. Probably just a few neighboring local variables that my
function was storing nearby on the stack, or maybe the return address on the
stack, or maybe the heap management data (block size field, free list pointer,
...) around the block of memory I allocated from the heap.

I wonder what the next pass of my loop will do now, or what will happen when
this function returns???

