/dev/clipboard corrupted

Thomas Wolff towo@towo.net
Tue Jul 3 22:14:00 GMT 2012


[taking this thread to cygwin-developers]

Corinna Vinschen:
> On Jun 29 11:47, Thomas Wolff wrote:
> > On 29.06.2012 11:24, Corinna Vinschen wrote:
> > >You know, we just love STCs.  Send you small test program here, plus a
> > >short instruction how you created the clipboard content and how to
> call
> > >the testcase to see the problem.
> > Sure, so here it is. Open clipboard.txt with notepad, ^A^C to copy
> > all, then run the program to see bytes skipped.
> > Actually it seems to skip as many bytes per read() as there were
> > additional UTF-8 bytes (more bytes than characters) in the preceding
> > read block.
> > Checking the code again, variable pos seems to be used both as an
> > index into the clipboard (WCHAR) and an offset to the resulting
> > string length (char) which would explain the effect (not having
> > checked all the details though as I'm not familiar with the used
> > APIs).
>
> Thanks for the testcase.  I applied a patch which is supposed to fix the
> problem.  It should be in the next developer snapshot.  Please give it
> a try.
The patch (loaded from CVS) seems to almost fix the issue but also 
another bug crept in.

* Looking at the code is quite confusing as long as I assumed 
sys_wcstombs would work like wcstombs;
    the latter is obviously designed to convert complete nul-terminated 
wcs strings only as
    there is no way to control the number of wcs characters, neither as 
consumed in the result
    (as your new comment also mentions) nor as setting a limit -
    the latter is apparently different, telling from the comment in 
strfuncs.cc.
    I had tried a patch using wctomb instead, as follows, but it didn't 
work;
    maybe for some reason the standard functions cannot be used in this 
context?
        int outlen = 0;
        /* Make sure buffer has room for max. length UTF-8 (or GB18030/UHC)
           plus final NUL;
           this does not work if the total buffer is shorter,
           so some read-ahead will be needed for a complete solution */
        while (outlen < (int) len - 4 && pos < (int) glen /* IS THIS 
CORRECT? */ )
          {
            int ret1 = wctomb ((char *) ptr + outlen, buf [pos]);
            if (ret1 == -1)
              {
                ((char *) ptr) [outlen] = 0x7F;   /* ?? */
                ret1 = 1;
              }
            pos ++;       /* clipboard buffer position */
            outlen += ret1; /* output size */
          }
        ret = outlen;

* The current (CVS) code will not work if even the first character to be 
converted
    needs more bytes than the buffer provides, e.g. if the application 
calls read() with length 1 only.
    Some extra buffering would be needed to make it work then.

* I assume the current code will also fail in non-UTF-8 locales;
    if the wcs block being converted contains a non-convertible character,
    it would abort since wcstombs returns -1
    (assuming here that sys_wcstombs behaves alike in this respect)
    and not even deliver the characters before the failing one.

* I had previously observed that with a read size of n only n-1 bytes 
would be delivered
    and thought this was on purpose because wcstombs appends a final nul 
to its result.
    Now n bytes are returned (if available) and in fact the byte behind 
the read() buffer is
    overwritten (see modified test program).

------
Thomas

-------------- next part --------------
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int
main (int argc, char * * argv)
{
	char * fn = "/dev/clipboard";
	int fd = open (fn, O_RDONLY | O_BINARY, 0);
	if (fd < 0) {
		exit (fd);
	}

	int out_tty = isatty (1);

	int filebuflen = 100;
	argc --;
	if (argc > 0) {
		int ret = sscanf (argv [1], "%d", & filebuflen);
	}
	char * filebuf = malloc (filebuflen + 1);
	filebuf [filebuflen] = 77;
	fprintf (stderr, "filebuflen %d (overflow byte %d)\n", filebuflen, filebuf [filebuflen]);

	int n;
	do {
		n = read (fd, filebuf, filebuflen);
		if (out_tty) {
			filebuf [n] = 0;
			printf ("read %d bytes: <%s> (overflow byte %d)\n", n, filebuf, filebuf [filebuflen]);
		} else {
			fprintf (stderr, "read %d bytes\n", n);
			write (1, filebuf, n);
		}
	} while (n > 0);

	close (fd);
}


More information about the Cygwin-developers mailing list