Your program, in this case mydiff, and the pager (less, or whatever you have selected as core.pager) are connected through a pipe. The OS has some limit on the amount of data that can be written into a pipe before the reader must clean some out, and the pager doesn't read the entire pipe before pausing, so at some amount of output, the pipe has filled up and your program is blocked in its write system call.
If the read end of the pipe goes away (by having the pager exit), two things happen at this point: the OS delivers a SIGPIPE signal to your program, and the OS has the write system call fail with an EPIPE error. Normally the first—the signal—kills your program before the second even occurs, but if your program were to catch or ignore SIGPIPE, the second would occur.
Here's an example in a job-control shell of SIGPIPE killing a process:
> cat book.pdf | : &
>
[1] Broken pipe cat book.pdf |
Done :
(Incidentally : here is the built in colon command, which is a no-op; it's a leftover from, I think, the Mashey shell that had goto as an external program.) Running this as a regular foreground process, the sequence is silent:
> cat book.pdf | :
>
This is because the shell does not complain about the died-of-SIGPIPE process, since "died of SIGPIPE" is quite normal.
For whatever reason, the git front end is noisier about this died-of-SIGPIPE case. If you don't use exec, it is the shell that sees the died-of-SIGPIPE. The shell absorbs that quietly and exits cleanly and git does not complain. If you do use exec, the shell is replaced with your program, and the git front end command sees the died-of-SIGPIPE status and complains.
One obvious cure is to leave the shell around. Another approach is to get the shell to ignore (not catch) SIGPIPE, then do the exec:
trap "" PIPE
As you noted in a comment-reply, catching SIGPIPE is no good: since exec replaces the current occupant of the address space, the OS resets all caught signals to their default disposition (which for SIGPIPE is "die of signal"). However, ignored signals remain ignored.
Depending on your program, this may be as bad or worse. For instance, when cat dies of SIGPIPE the shell is silent, but when cat sees write fail with EPIPE it complains:
$ cat book.pdf | :
$ trap "" PIPE
$ cat book.pdf | :
cat: stdout: Broken pipe
(this is on FreeBSD; different OSes vary slightly, depending on how careful and clever their utilities are).