Vviewpoints
DOI: 10.1145/2380656.2380667
Article development led by
queue.acm.org
Kode Vicious
can More code
Mean Fewer Bugs?
Dear KV,
One of the coders I work with keeps
removing my calls to system() from
my code, insisting it is better to write
code that does the work I am doing via
the shell. He keeps saying it is far safer
to code using the language we are using than to call out to the shell to get
this work done. I would believe that if
he did not add 10 to 20 lines of code
just to do what I do in one line with
system(). How can increasing the
number of lines of code decrease the
number of bugs?
happy with the one-Liner
Dear one,
You almost had me with your appeal
to simplicity, that having a single line
with system() on it reduces the potential for bugs. Almost, but not quite.
ImAgE BY VIKTORUS
When you call out to the shell from
any language, you are not using a single line of code, but thousands. Calling
a shell at this point is like using a nuke
to kill a flea. That flea will be very dead
when you are done, but you have also
wasted a lot of energy in killing it, and
it may result in collateral damage. Each
and every call to system() is trusting
all that underlying code, and the issue
is not only that there are a lot of lines
under there, but also that the things
the shell can do are extremely powerful—it is probably the most powerful
program on any system.
A command shell on any system—
Unix, Windows, or otherwise—is there
to command the system, and it has accreted to itself, over time, the ability to
do things to the system in a single line
that really should require a bit more
thought. The obvious example is moving and removing files. I would actually
like to think that most programmers
know better than to do something like
calling system() with an rm command, in particular one in which they
supply unchecked user input to the
call to system(). While I say “I would
like to think that,” a voice—a very loud
voice—in the back of my head is screaming, “It’s not so! It’s not so! They’ll do it!
Stop them now!” I hate that voice, but
no matter how I try to drown it out—and
I have tried—there it remains.
A worse offense than invoking the
rm command in a system command
is calling a shell script via system().
Why? Because the poor sap reading
your code later will probably have no
idea what the script does. I am sure it
will have a descriptive name such as
update_sales_2.sh, and that it will
be checked in to the source repository
rather than being stored in the /home/
bob/update_test2/ directory, but
perhaps it won’t, and the fragile setup I
describe here will ring true: when Alice
comes to read the code, she will then
have to go read update_sales_ 2.
sh, so long as she has read access to
Bob’s home directory. She will be reading it at 3 A.M. when something has
broken, and this will all go well and everyone will live happily ever after.
Perhaps my very favorite abuse of
the system() routine in code is when
it is used to build up a complex pipeline of commands. Using pipes in a call
to system() in a program is a fine way
to launch a fork bomb into your system, especially if the pipes are built up
on the fly.
Running a complex piped command from a shell by hand has less
risk of hammering the machine because humans are slow—and supposedly they are paying attention to what
they are doing. Once you put a set of