
 C No Evil - wglb
http://blog.regehr.org/archives/574?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+EmbeddedInAcademia+%28Embedded+in+Academia%29
======
tedunangst

        #define continue break
    

There's my choice. It's one of the few that will actually compile and the
runtime effect is not super immediately detectable.

~~~
cpeterso
or break switch statements with:

    
    
      #define break

------
dschoon
Some of the most frustrating problems I've seen are due to misunderstanding or
rare semantics rather than mistakes. Examples might include the specifics of
floating-point math, or exactly how numeric coercion works. This is especially
bad when the result isn't easy to eyeball as right or wrong.

For example, we could force a double-valued transcendental function to float
and back for a small loss of precision in normal cases:

    
    
        #define sin(d) ((double)sinf(d))
    

Which yields...

    
    
        double i =  10
        --> i    =  10.0000000000
        sin(i)   = -0.5440211109
        sinf(i)  = -0.5440211296
        delta    =  0.0000000187
        
        double i =  0.25
        --> i    =  0.2500000000
        sin(i)   =  0.2474039593
        sinf(i)  =  0.2474039644
        delta    = -0.0000000051
        
        double i = 9999999.999999
        --> i    = 9999999.9999989998
        sin(i)   =  0.4205487007
        sinf(i)  =  0.4205478132
        delta    =  0.0000008875
    

(Format string was %25.10f, fwiw.)

Another idea: Let's say we know the application relies on rand() to produce
the correct distribution for testing, or maybe to generate session keys.
Changing the semantics of the RNG won't result in a compiler bug, but it might
result in the tests failing to cover all cases, or a horrible security breach.

------
wulczer
I think #define volatile is by far the sneakiest.

The rest would probably be found quite quickly, but omitting volatiles could
lead to hard to detect bugs that will only manifest themselves under specific
circumstances.

~~~
psykotic
> I think #define volatile is by far the sneakiest.

The only legitimate reasons for using volatile generally involve memory-mapped
IO and POSIX signal handlers. C's volatile is nothing like Java's volatile and
has very weak semantics. With lock-based code you generally have nothing to
worry about because lock/unlock has load-acquire/store-release semantics. But
if you're writing lock-free code, volatile is useless in general and you need
to think carefully about how atomicity is affected by memory alignment and
operand size (e.g. a byte write that might look atomic implicitly turns into a
non-atomic read-modify-write), explicit memory barriers, etc.

So defining away volatile won't actually impact most applications unless
they're relying on very compiler-specific behavior.

~~~
wulczer
A typical usage of volatile, and one that bit me many times is using longjmp,
for which the man page says:

    
    
      The values of automatic variables are unspecified after a call to longjmp() if they meet all the following criteria:
      · they are local to the function that made the corresponding setjmp(3) call;
      · their values are changed between the calls to setjmp(3) and longjmp(); and
      · they are not declared as volatile.
    

I've had bugs that made me go half-crazy before someone reminded me that you
have to use volatile in these situations.

~~~
mattgreenrocks
I assume that's a side effect of how the execution context is restored? If a
nonvolatile local was stored in a register, and passed by address to a
function that modified it before longjmp(), then the saved register value
would clobber the updated one.

~~~
psykotic
You don't need to pass it by address to a function. Something like this could
trigger it:

    
    
        // region 1:
        // x is allocated to register r1
        int x = 0; // store 0 to r1
        jmpbuf jb;
        if (setjmp(jb) == 0) {
            // region 2:
            // x is re-allocated to r2, so r1 is copied to r2
            x = 42; // store 42 to r2
            longjmp(jb, 1);
        }
        // region 3:
        // x is allocated to r1
        printf("%d\n", x); // load from r1
    

The compiler is allowed to allocate the same variable to different locations
at different points in the program. At re-allocation boundaries, it will
insert register moves or stack spills or whatever. The problem in the example
is that the longjmp() crosses a re-allocation barrier, so the store to r2
won't be registered as a store to x in region 3.

Actually, this would still occur even if x was always allocated to r1. The
reason is that before calling setjmp() the compiler spills x to the stack, so
the callee can use the registers for its own use, and on returning (either via
longjmp() or the first time through) it will restore x from the value on the
stack.

I tried the example above with GCC. At the default optimization level it
printed 42. But with -O2 it printed 0. Looking at the assembly code, it's
actually even worse than I described. The compiler has treated the longjmp()
akin to an exit() and so has determined that the x = 42 is actually a no-op
that can be eliminated. This is similar to how in printf("1"); exit(0);
printf("2"); the compiler will actually remove the second printf() as dead
code from the executable.

So, in conclusion, there seems to be a whole bunch of ways in which the
compiler could screw this up while staying within the bounds of standards-
acceptable behavior.

------
afhof
Obviously library dependent, but I think this would make me pull my hair out:

#define pthread_mutex_lock(x)

#define pthread_mutex_unlock(x)

------
elevenE
Can anyone explain what effect

    
    
      #define goto
    

would have? It doesn't looks valid, because if I have

    
    
      myLabel:
      /* some code*/
      goto myLabel;
    

would produce

    
    
      myLabel;
    

Which, as far as I know shouldn't compile because it expects either a normal
expression or a definition/declaration and _myLabel;_ doesn't appears to be
any of them. (Maybe I'm missing something)

------
bdonlan

        #define free(x)
    

Most tests still pass, but once the program's been running for a while you'll
get a nice memory leak. Fails if your mortal enemy runs leak checks as part of
their standard test suite or other QA, or has a high enough allocation rate to
quickly turn up such issues.

~~~
Someone
Improvement: include some static counter, and only skip the free after a few
million (billion?) calls. If possible, also make the thing random, and limit
skipping free to a limited range of block sizes. The latter provides a nice
false trail for investigators (hm, it is leaking only struct foo...)

Problem of course is to find a nice size range for the program at hand.

------
lukesandberg
This is pretty much straight out of the daily wtf:
<http://thedailywtf.com/Articles/The-Disgruntled-Bomb.aspx>

~~~
raldi
We have a winner:

#define if(x) if(rand()<0.0001 && (x))

~~~
iam
if(rand()>=0.0001 && (x))

that way it will fail extremely rarely and be even harder to detect!

~~~
raldi
You're right, they either need your change or a switch to ||

------
tptacek
#define free(x) free(x + 1)

#define malloc(x) malloc(random())

~~~
tedunangst
The free one at least will be detected immediately with a good libc, but nice
idea. It gives me another idea though:

    
    
        #define free(x) do { free(x); x = NULL; } while (0)
    

Assuming you can turn it off just before shipping, this will hide many forms
of double free during development which then show up when the evil line is
deleted.

~~~
1amzave
That assumes 'x' is an lvalue, which it may very well not be (thus causing
compilation errors, which would presumably get caught pretty quickly).

~~~
tedunangst
I'm having a very hard time thinking of an example where you'd free an rvalue.
Function return, maybe, but without using the value? It (almost) had to be an
lvalue in order to get the malloc into it. Ah, an unconst cast. free((void
*)constx), but lots of compilers don't catch that. Is there something else you
were thinking of?

There's also people doing stupid shit like free(&x), but those people don't
need evil macros to dick up their code. :)

~~~
copper
Function calls seem right - particularly if they're badly written. Also, this
macro might give curious results when passed in ptr++ .

While this is C++, I've actually seen this particular construct: delete new
SomeClass(...);

used as, basically, an eye-poppingly clever way of initializing something,
doing work, and then cleaning up after.

~~~
tedunangst

        { SomeClass makeitso; }
    

:)

Also, free(ptr++) is broken by design, the post increment value is useless.
But free(*ptr++) is a good case.

~~~
copper
> free(*ptr++)

Yes, of course - that's what I thought I'd written. Clearly not :)

------
floppydisk
Some buddies and I were messing around with ways we could sneakily inject one
hidden #define somewhere in a C project to make it look like a segfault. We
ended up with #define printf to print out "segfault" but GCC always threw
warnings, so it didn't have much practicality for use in a joke.

~~~
tedunangst
Pre C99? Cheap hack using variadic macros:

    
    
       #define printf(...) printf(__VA_ARGS__); puts("\n\n\n\nFAIL!")

~~~
floppydisk
Yes, pre-C99. I'm going to have to try that now.

------
seclorum
Here's mine:

    
    
        __attribute__((constructor)) void __maiin(void)
        {
            if (rand() < 0.05) exit();
            //if (rand() < 0.05) close(1);
            //if (rand() < 0.05) main(); // and so on ..
        }
    
    

The program will randomly quit before main() is executed.

------
bryanallen22
#define int char

I did this one to a friend (briefly) during school.

------
jakelear
An interesting, albeit not that valuable, challenge. It's a fun little
question, but it's not even valuable as a black hat exercise. It's just a non-
sensical hypothetical.

~~~
Symmetry
Its supposed to be interesting from the perspective of people trying to write
reliable C code, not do actual harm.

------
barrkel
I would prefer:

    
    
        #define assert(x) ((void)(x))
    

Most of these would cause an immediate flood of hints and / or warnings; but
an assert that did nothing but evaluate its argument could lurk for some days,
especially if the developers in question don't spelunk with a debugger very
often.

~~~
cperciva
I don't get it. In (non-wildly-buggy) code evaluating the argument to assert()
is required to (a) succeed, and (b) have no side effects, so what would such a
definition accomplish?

~~~
barrkel
Assumptions:

* asserts are used in a defensive programming style to state invariants

* the enemy developers will be reasoning about the code assuming that asserts which didn't fire were true

* when debugging, they'll read the code and prematurely dismiss valid theories as to why the bug exists based on what they read in the assertions

~~~
cperciva
Sure, but I don't think this matches the problem statement -- if the product
is within a week or two of shipping, it should be long past the point where
developers are tracking down bugs by using asserts to exclude possible code
paths.

If the problem was to slow down _early_ development I'd absolutely agree with
you.

------
leif

        #define rand() (rand() % 100)

------
cpeterso

      #define memmove memcpy
      #define default default: break; case 0xfeceface

------
killerswan
Reminds me of Sony... Perhaps they had this someplace: #define rand(x) 4

------
Turing_Machine
#define fopen(A,B) ((rand() % 1000 == 0) ? fopen(A,"w") : fopen(A,B))

------
CPlatypus
I think redefining volatile wouldn't be harmful enough because so few people
use volatile correctly anyway. By contrast, the break/continue or double-free
suggestions would show up too quickly. I don't think I can come up with
anything as insidious as some of the "one in a million" suggestions, but I
like this one for its brevity.

#define do

You could even slip that into a makefile (-Ddo=) and it might not be noticed.

~~~
epidemian
I think that would cause an infinite loop on most usages of do/while, thus
making the problem (probably not the cause hehe) quickly noticeable.

------
Que
Interesting header, but why would anyone want to cause someone else so much
trouble trying to release a product?

~~~
burgerbrain
It's just a throwaway scenerio to wrap around an interesting problem...

