Table of Contents

A quick one

Just a quick something to keep this site alive.

These two issues were nothing that got me fuming angry, but my boss was not amused when I was blindsided by these two issues in a production environment.

One: bash ''tee'' and return values

There is this nice UNIX tool named `tee` that writes its standard input to a file without actually consuming it. It is very useful in scripts where you want to print the proceedings to screen while at the same time logging them somewhere:

someCommand | tee -a logfile.txt # '-a' to append instead of overwriting

It gets ugly, though, when you add this kind of logging to a script retroactively, and fail to realize that the next step in the original script was to check if someCommand was successful:

someCommand | tee -a logfile.txt
if [ $? != 0 ]; then

Congratulations: Because $? returns the exit code of the last command executed, you just checked whether tee succeeded (e.g., in logging someCommand’s failure).

Luckily, bash offers a way out: The array PIPESTATUS carries the individual exit codes of all commands in the pipe chain.

someCommand | tee -a logfile.txt
if [ {$PIPESTATUS[0]} != 0 ]; then

Two: ''va_arg'' and C++ references don’t mix.

Consider:

#include <string>
#include <cassert>
 
using namespace std;
 
void foo( std::string & parmN, ... )
{
    va_list ap;
    va_start( ap, parmN );
    int i = va_arg( ap, int );
    va_end( ap );
}
 
int main()
{
    std::string broken;
    foo( broken, 42 );
    return 0;
}

The variable i will most likely not be set to 42.

The reason is that most implementations of va_arg will take the address of parmN using the address operator &. For a C++ reference, like in this case, this will yield the address of the referenced variable. You will not get the address of parmN, but the address of broken, and whatever you pull out of va_arg will not be what you expected.


These two bastiches caused me some hurt. Be warned.