HOME BLOG ARCHIVE TAGS

Things I have seen

December 24, 2015

I have seen weird things in software development. Very subtle and/or amusing stuff (to say the least). Several examples follow.

THEWHO KNOWSMACHINE

Let’s disregard immediate topics: integer sizes, volatile variables, type punning, strict aliasing issues, etc. Even legendary W. Richard Stevens couldn’t foresee this one coming in practice:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define LITTLE_ENDIAN     0
#define BIG_ENDIAN        1
#define WHO_KNOWS_ENDIAN  2

//
// NOTE: 'char *' casts below are legal; [un]signed char pointers can
// alias other types; the inverse is not always guaranteed;
//
int endianness_detect()
{
    int c = 0x04030201;

    if ( *((char *)&c) == 1 ) {
        c = LITTLE_ENDIAN;
    }
    else if ( *((char *)&c) == 4 ) {
        c = BIG_ENDIAN;
    }
    else {
        c = WHO_KNOWS_ENDIAN;
    }

    return c;
}

UNIX Network Programming Vol.1 presents one proper way to do endianness checks. But some folks may have taken Stevens way too literally. For non mixed-endian architectures, the “who knows” branch is ridiculous.

Furthermore, modern optimizing compilers can make our lives miserable. Just take a look at the disassembly of above (less aggressively optimized) function, compiled with MSVC++:

1
2
.text!0x440C8E81    xor     eax, eax
.text!0x440C8E83    retn

Can you spot it? Compiler knew the target was IA-32, and removed “superfluous” tests. This is dead code elimination in action. All related branches can be dropped from final binary.

Rob Pike may have a point, after all.

LET’S HARD CHECK, JUST IN CASE

On the trichotomy side of bizarre things, seen in code from Brazilian developers with strong mainframe background (translated from COBOL to Python):

1
2
3
4
5
6
7
def handle_storage(s):
    if s >= K:
        trigger_big(s)
    elif s < K:
        trigger_low(s)
    else:
        trigger_invalid(s)

Isn’t that special?

LIKE THERE’S NO TOMORROW

Win32 SEH for those who really care, but program in the best Win32s tradition:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
bool something_dangerous()
{
    __try {
        dangerous_call();
    }
    __except( EXCEPTION_EXECUTE_HANDLER ) {
        return false;
    }

    return true;
}

Like ignoring uncontrolled SIGSEGVs on POSIX systems, SEH is tricky and harmful.

ONE HELL OF A PAD

1
2
3
4
5
6
7
8
#define MAX_BUFFER_LEN  128

(...)

// padding avoids access-violation
char buf[MAX_BUFFER_LEN + 2048];

(...)

This one was hidden inside the core of a complex ATL based COM wrapper. Of course, there were access-violations.

(“OLDMEYERS’) SINGLETONS THAT WEREN’T

Once upon a time, everybody loved Scott Meyerssingletons:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Singleton
{
public:
    static Singleton &instance()
    {
        static Singleton i_;
        return i_;
    }

protected:
     Singleton() { /*(...)*/ }
    ~Singleton() { /*(...)*/ }
};

// (...)

Singleton &s = Singleton::instance();

// (...)

Except when they didn’t deliver:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
;
; "Singleton *Singleton::instance()"
;
;  NOTE: global/internal compiler flag at 40301Ch is set/checked,
;  to manage 'i_' lifecycle
;
mov    cl,byte ptr [$S1 (40301Ch)]
mov    eax,1
test   al,cl
jne    Singleton::instance+15h (401035h)
or     dword ptr [$S1 (40301Ch)],eax
mov    eax,offset i_ (403018h) ; &i_
ret

The disassembly came from an old MSVC++ compiled binary; no atomic test-and-set is employed. Typical implementations of the pattern leveraged thread-unsafe implicit code generation like this, and were prone to very hard to find race conditions.

Fortunately, since C++11, static initialization takes concurrent execution into account (double-checked locking pattern is also fixed).

CONCLUSION

Don’t know for sure. Maybe software is hard, and one can get lost.