devdraw, acme, snarfer: remove 64KB snarf buffer limit

The snarf code silently dropped text larger than SnarfSize (64KB),
causing paste to produce nothing. Replace the static clip buffer
with a dynamically allocated one, remove all the size checks, and
read the actual X11 property size instead of capping at SnarfSize.
This commit is contained in:
David du Colombier
2026-03-16 21:17:28 +00:00
committed by Dan Cross
parent ae4fdf4268
commit 0d87d4b75e
5 changed files with 48 additions and 39 deletions

View File

@@ -547,10 +547,6 @@ extern void drawsetdebug(int);
/* /*
* Snarf buffer * Snarf buffer
*/ */
enum
{
SnarfSize = 64*1024
};
char *getsnarf(void); char *getsnarf(void);
void putsnarf(char*); void putsnarf(char*);

View File

@@ -1090,11 +1090,6 @@ iconinit(void)
* fd here rather than use snarffd * fd here rather than use snarffd
*/ */
/* rio truncates larges snarf buffers, so this avoids using the
* service if the string is huge */
#define MAXSNARF 100*1024
void void
acmeputsnarf(void) acmeputsnarf(void)
{ {
@@ -1104,8 +1099,6 @@ acmeputsnarf(void)
if(snarfbuf.nc==0) if(snarfbuf.nc==0)
return; return;
if(snarfbuf.nc > MAXSNARF)
return;
fmtstrinit(&f); fmtstrinit(&f);
for(i=0; i<snarfbuf.nc; i+=n){ for(i=0; i<snarfbuf.nc; i+=n){

View File

@@ -1109,7 +1109,7 @@ rpc_getsnarf(void)
void void
rpc_putsnarf(char *s) rpc_putsnarf(char *s)
{ {
if(s == nil || strlen(s) >= SnarfSize) if(s == nil)
return; return;
dispatch_sync(dispatch_get_main_queue(), ^(void) { dispatch_sync(dispatch_get_main_queue(), ^(void) {

View File

@@ -1454,9 +1454,8 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
struct { struct {
QLock lk; QLock lk;
char buf[SnarfSize]; char *buf;
#ifdef APPLESNARF #ifdef APPLESNARF
Rune rbuf[SnarfSize];
PasteboardRef apple; PasteboardRef apple;
#endif #endif
} clip; } clip;
@@ -1498,7 +1497,7 @@ _xgetsnarffrom(Xwin *w, XWindow xw, Atom clipboard, Atom target, int timeout0, i
/* get the property */ /* get the property */
xdata = nil; xdata = nil;
XGetWindowProperty(_x.display, w->drawable, prop, 0, SnarfSize/sizeof(ulong), 0, XGetWindowProperty(_x.display, w->drawable, prop, 0, (len+3)/4, 0,
AnyPropertyType, &type, &fmt, &len, &dummy, &xdata); AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){ if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){
if(xdata) if(xdata)
@@ -1538,6 +1537,8 @@ rpc_getsnarf(void)
// TODO check more // TODO check more
if(xw == w->drawable){ if(xw == w->drawable){
mine: mine:
data = nil;
if(clip.buf != nil)
data = (uchar*)strdup(clip.buf); data = (uchar*)strdup(clip.buf);
goto out; goto out;
} }
@@ -1577,12 +1578,11 @@ __xputsnarf(char *data)
XButtonEvent e; XButtonEvent e;
Xwin *w; Xwin *w;
if(strlen(data) >= SnarfSize)
return;
qlock(&clip.lk); qlock(&clip.lk);
xlock(); xlock();
w = _x.windows; w = _x.windows;
strcpy(clip.buf, data); free(clip.buf);
clip.buf = strdup(data);
/* leave note for mouse proc to assert selection ownership */ /* leave note for mouse proc to assert selection ownership */
_x.putsnarf++; _x.putsnarf++;
@@ -1627,8 +1627,12 @@ if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d (sizeof
/* text/plain;charset=utf-8 is used by xfce4-terminal 1.0.4 */ /* text/plain;charset=utf-8 is used by xfce4-terminal 1.0.4 */
/* if the target is STRING we're supposed to reply with Latin1 XXX */ /* if the target is STRING we're supposed to reply with Latin1 XXX */
qlock(&clip.lk); qlock(&clip.lk);
if(clip.buf)
XChangeProperty(_x.display, xe->requestor, xe->property, xe->target, XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)); 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
else
XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
8, PropModeReplace, (uchar*)"", 0);
qunlock(&clip.lk); qunlock(&clip.lk);
}else{ }else{
if(strcmp(name, "TIMESTAMP") != 0) if(strcmp(name, "TIMESTAMP") != 0)
@@ -1674,6 +1678,8 @@ _applegetsnarf(void)
} }
flags = PasteboardSynchronize(clip.apple); flags = PasteboardSynchronize(clip.apple);
if(flags&kPasteboardClientIsOwner){ if(flags&kPasteboardClientIsOwner){
s = nil;
if(clip.buf != nil)
s = strdup(clip.buf); s = strdup(clip.buf);
qunlock(&clip.lk); qunlock(&clip.lk);
return s; return s;
@@ -1716,14 +1722,21 @@ _appleputsnarf(char *s)
{ {
CFDataRef cfdata; CFDataRef cfdata;
PasteboardSyncFlags flags; PasteboardSyncFlags flags;
Rune *r;
int n;
/* fprint(2, "appleputsnarf\n"); */ /* fprint(2, "appleputsnarf\n"); */
if(strlen(s) >= SnarfSize)
return;
qlock(&clip.lk); qlock(&clip.lk);
strcpy(clip.buf, s); free(clip.buf);
runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s); clip.buf = strdup(s);
n = utflen(s) + 1;
r = malloc(n * sizeof(Rune));
if(r == nil){
qunlock(&clip.lk);
return;
}
runesnprint(r, n, "%s", s);
if(clip.apple == nil){ if(clip.apple == nil){
if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){ if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
fprint(2, "apple pasteboard create failed\n"); fprint(2, "apple pasteboard create failed\n");
@@ -1733,17 +1746,20 @@ _appleputsnarf(char *s)
} }
if(PasteboardClear(clip.apple) != noErr){ if(PasteboardClear(clip.apple) != noErr){
fprint(2, "apple pasteboard clear failed\n"); fprint(2, "apple pasteboard clear failed\n");
free(r);
qunlock(&clip.lk); qunlock(&clip.lk);
return; return;
} }
flags = PasteboardSynchronize(clip.apple); flags = PasteboardSynchronize(clip.apple);
if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){ if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
fprint(2, "apple pasteboard cannot assert ownership\n"); fprint(2, "apple pasteboard cannot assert ownership\n");
free(r);
qunlock(&clip.lk); qunlock(&clip.lk);
return; return;
} }
cfdata = CFDataCreate(kCFAllocatorDefault, cfdata = CFDataCreate(kCFAllocatorDefault,
(uchar*)clip.rbuf, runestrlen(clip.rbuf)*2); (uchar*)r, runestrlen(r)*2);
free(r);
if(cfdata == nil){ if(cfdata == nil){
fprint(2, "apple pasteboard cfdatacreate failed\n"); fprint(2, "apple pasteboard cfdatacreate failed\n");
qunlock(&clip.lk); qunlock(&clip.lk);

View File

@@ -54,11 +54,8 @@ AUTOFRAMEWORK(Carbon)
#undef time #undef time
AUTOLIB(draw) /* to cause link of X11 */ AUTOLIB(draw) /* to cause link of X11 */
enum { char *snarf;
SnarfSize = 65536 Rune *rsnarf;
};
char snarf[3*SnarfSize+1];
Rune rsnarf[SnarfSize+1];
XDisplay *xdisplay; XDisplay *xdisplay;
XWindow drawable; XWindow drawable;
Atom xclipboard; Atom xclipboard;
@@ -98,6 +95,7 @@ main(int argc, char **argv)
break; break;
}ARGEND }ARGEND
snarf = strdup("");
if((xdisplay = XOpenDisplay(nil)) == nil) if((xdisplay = XOpenDisplay(nil)) == nil)
sysfatal("XOpenDisplay: %r"); sysfatal("XOpenDisplay: %r");
drawable = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay), drawable = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay),
@@ -256,18 +254,16 @@ xgetsnarf(void)
return nil; return nil;
/* get the property */ /* get the property */
data = nil; data = nil;
XGetWindowProperty(xd, drawable, prop, 0, SnarfSize/sizeof(ulong), 0, XGetWindowProperty(xd, drawable, prop, 0, (len+3)/4, 0,
AnyPropertyType, &type, &fmt, &len, &dummy, &xdata); AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
if(xdata == nil || (type != XA_STRING && type != xutf8string) || len == 0){ if(xdata == nil || (type != XA_STRING && type != xutf8string) || len == 0){
if(xdata) if(xdata)
XFree(xdata); XFree(xdata);
return nil; return nil;
} }
if(strlen((char*)xdata) >= SnarfSize){ free(snarf);
snarf = strdup((char*)xdata);
XFree(xdata); XFree(xdata);
return nil;
}
strcpy(snarf, (char*)xdata);
return snarf; return snarf;
} }
@@ -286,8 +282,16 @@ appleputsnarf(void)
#ifdef __APPLE__ #ifdef __APPLE__
CFDataRef cfdata; CFDataRef cfdata;
PasteboardSyncFlags flags; PasteboardSyncFlags flags;
int n;
runesnprint(rsnarf, nelem(rsnarf), "%s", snarf); if(snarf == nil)
return;
n = utflen(snarf) + 1;
free(rsnarf);
rsnarf = malloc(n * sizeof(Rune));
if(rsnarf == nil)
return;
runesnprint(rsnarf, n, "%s", snarf);
if(PasteboardClear(appleclip) != noErr){ if(PasteboardClear(appleclip) != noErr){
fprint(2, "apple pasteboard clear failed\n"); fprint(2, "apple pasteboard clear failed\n");
return; return;