Holy cow, I wrote a book!
There are some basic ground rules that apply to all system programming,
so obvious that most documentation does not bother explaining them
because these rules should have been internalized by practitioners
of the art to the point where they need not be expressed.
In the same way that when plotting driving directions
you wouldn't even consider taking a shortcut through somebody's
backyard or going the wrong way down a one-way street,
and in the same way that an experienced chess player doesn't even consider
illegal moves when deciding what to do next,
an experienced programmer doesn't even consider violating the following
basic rules without explicit permission in the documentation to the contrary:
(Remember, every statement here is a basic ground rule, not an
absolute inescapable fact. Assume every sentence here is
prefaced with "In the absence of indications to the contrary".
If the caller and callee have agreed
on an exception to the rule, then that exception applies.
a pointer is prototyped as volatile
is explicitly marked as "This value can change from another thread,"
so the rule against modifying function parameters does not apply to
such a pointer.)
Coming up with this was hard,
in the same way it's hard to come up with a list of
illegal chess moves.
The rules are so automatic that they aren't really rules
so much as things that simply are and it would be crazy
even to consider otherwise.
As a result, I'm sure there are other "rules so obvious they need
not be said" that are missing.
(For example, "You cannot terminate a thread while it is inside
somebody else's function.")
One handy rule of thumb for what you can do to a function call
is to ask, "How would I like it if somebody did that to me?"
(This is a special case of the "Imagine if this were possible" test.)