While not strictly related to C or C++ programming, I thought I'd ask
about this here...
Many years back (mid 1990s) a friend of mine discovered a DOS program he
was using would freeze his PC (or perhaps cause it to spontaneously
reboot) after it was left running unattended for several days.
Eventually he somehow tracked it down to some code that triggered a bug
in the Novell Netware client on his machine. Essentially, if the
program called INT 0x21, function 0x4E (findfirst - the DOS equivalent
of Windows' FindFirstFile() function) without ever calling function 0x4F
(findnext), and repeated this process for a while, the system couldn't
cope. Presumably it was running out of memory and not handling that
error properly.
Normally you'd use the pair of functions like this:
// psuedocode
result = findfirst("*.*")
while result.returncode != 0:
print result.filename
result = findnext(result)
Instead, it was used to check whether a particular file existed:
// psuedocode again
result = findfirst("COMMAND.COM")
if result.returncode != 0:
print result.filename + " exists"
else:
print result.filename + " was not found"
I'm not sure the designers of the 0x4E/0x4F functions had the above
example in mind when they invented it, but we would probably need to
travel back 25 years to find out.
When I began writing this e-mail, I was going to ask what this type of
bug would be classified as, but after reading what I've written, and
based on a few assumptions, I suppose it was just a type of memory leak.
Back in the DOS days a memory leak could have severe consequences,
particularly if programs were not designed to detect them. Although,
perhaps these days you could still have a serious problem if you wrote a
Windows or Linux driver that leaked memory if its API was misused by an
application. Maybe the trick is to have the application allocate the
memory instead. But there are probably times where that isn't
practical. Maybe this type of bug is more common than I think?
And just to finish off, depending on how the 0x4E/0x4F pair of functions
worked internally, another bug could pop up:
result = findfirst("*.BAT")
while result.returncode != 0:
print result.filename
nested_result = findfirst("*.EXE")
while nested_result != 0:
print nested_result.filename
nested_result = findnext(nested_result)
result = findnext(result)
If the second (nested) call to findfirst() obliterated the initial
findfirst()'s internal memory, what would the final call to findnext()
do? A simpler example of what I mean:
result = findfirst("*.BAT")
second_result = findfirst("*.EXE")
result = findnext(result)
Anyway, I'm not sure if much of this made sense...
Regards
Andrew