I reproduced the issue again and investigated. Since I'm unsure how to determine information about the Lisp system within GDB, I used debug statements in C and Lisp to arrive at the following description of what happens, additive to my previous description:

My after-change-functions, in order, are:
   semantic-change-function
   c-after-change
   jit-lock-after-change

search_regs.start[0] first takes on the incorrect value inside c-after-change's call to save-match-data. Since c-after-change code seems correct, I determined that the match-data function begins returning the incorrect value during semantic-change-function. I am using CEDET r8557.

>> I suppose that caveat would pin the bug on one of the third party
>> packages I use. However, why couldn't Emacs save off the match-data
>> itself and restore it after the after-change-functions? Is there any
>> legit situation where a change hook would want to change the
>> match-data in effect after the change hook returns?

Stefan> There are many cases where an after-change-function won't use regular
Stefan> expressions at all.

The answer doesn't seem to fit the question, so I'll rephrase: Why does Emacs allow after-change-functions to change the match-data beyond its scope? Or: why doesn't the signal_after_change C function do like set-match-data instead of leaving it to client change hooks to do so?