Failing to fully specify what happens with input buffers. Returned buffers too.
For example, ponder a hypothetical (yeah, right) library routine–let’s call it, say, new_form
which takes a NULL (rather than NUL, which is different, but you knew that) terminated buffer of field pointers. You call it and the fields in the buffer are now part of a brand-spanking new form. Yay, us. Anything that handles even part of form and field stuff is welcome, as it’s a pain (though I could rant about ncurses for a while. But not today) to handle.
But… what happens to that buffer? Is it now the property of the form library? Did it make a copy and now I can delete my copy? If the docs don’t say, I don’t know.
Looking at the source is no help–I don’t care what the source says, I care about what guarantees are made by the API. Just because the library makes a copy now (it doesn’t, I looked, but that’s a separate rant) doesn’t mean that it has to in the future. Someone might, at some random time after now, decide that since the behaviour’s unspecified and as such open to change. I’m perfectly fine with that, too, as flexibility is good, and I for one have no compunctions about viciously and egregiously changing behaviours that I’ve promised are undefined. (I take a certain glee in it, in fact 🙂 But I should at least know what behaviours are undefined, dammit! Don’t make me guess.
APIs are promises of behavior. Be specific with your promises, and clear about what you’re not promising.