From: cinap_lenrek Date: Fri, 2 Apr 2021 13:51:15 +0000 (+0200) Subject: acme: fix suicide *and* resource leak in ecmd.c (thanks igor) X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=afa5800b5b5782d71dd9347629b30bde0ac18635;p=plan9front.git acme: fix suicide *and* resource leak in ecmd.c (thanks igor) To reproduce the suicide try running the following in acme: • 'Edit B cpu% broke echo kill>/proc/333310/ctl # acme cpu% acid 333310 /proc/333310/text:amd64 plan 9 executable /sys/lib/acid/port /sys/lib/acid/amd64 acid: lstk() edittext(nr=0x31,q=0x0,r=0x45aa10)+0x8 /sys/src/cmd/acme/ecmd.c:135 xfidwrite(x=0x461230)+0x28a /sys/src/cmd/acme/xfid.c:479 w=0x0 qid=0x5 fc=0x461390 t=0x1 nr=0x100000031 r=0x45aa10 eval=0x3100000000 a=0x405621 nb=0x500000001 err=0x419310 q0=0x100000000 tq0=0x80 tq1=0x8000000000 buf=0x41e8d800000000 xfidctl(arg=0x461230)+0x35 /sys/src/cmd/acme/xfid.c:52 x=0x461230 launcheramd64(arg=0x461230,f=0x22357e)+0x10 /sys/src/libthread/amd64.c:11 0xfefefefefefefefe ?file?:0 The suicide issue is caused by the following chain of events: • /sys/src/cmd/acme/ecmd.c:/^edittext is called at /sys/src/cmd/acme/xfid.c:479 passing nil as its first parameter: ... case QWeditout: r = fullrunewrite(x, &nr); if(w) err = edittext(w, w->wrselrange.q1, r, nr); else err = edittext(nil, 0, r, nr); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... ...and /sys/src/cmd/acme/ecmd.c:/^edittext dereferences the first parameter that is *nil* at the first statement: char* edittext(Window *w, int q, Rune *r, int nr) { File *f; f = w->body.file; ^^^^^^^^^^^^^^^^^^^^^ This will crash if 'w' is *nil* switch(editing){ ... Moving the the derefernce of 'w' into the case where it is needed (see above patch) fixes the suicude. The memory leak is fixed in /sys/src/cmd/acme/ecmd.c:/^filelist. The current implementation of filelist(...) breaks its contract with its caller, thereby leading to a memory leak in /sys/src/cmd/acme/ecmd.c:/^B_cmd and /sys/src/cmd/acme/ecmd.c:/^D_cmd. The contract /sys/src/cmd/acme/ecmd.c:/^filelist seems to have with its callers is that in case of success it fills up a 'collection' that callers can then clear with a call to clearcollection(...). The fix above honours this contract and thereby removes the leak. After you apply the patch the following two tests should succeed: • Execute by select and middle click in a Tag: 'Edit B lib/profile' • Execute by select and middle click in a Tag: 'Edit B body.file; switch(editing){ case Inactive: return "permission denied"; case Inserting: + f = w->body.file; eloginsert(f, q, r, nr); return nil; case Collecting: @@ -157,11 +157,13 @@ filelist(Text *t, Rune *r, int nr) if(nr == 0) return nil; r = skipbl(r, nr, &nr); - if(r[0] != '<') - return runestrdup(r); - /* use < command to collect text */ clearcollection(); - runpipe(t, '<', r+1, nr-1, Collecting); + if(r[0] != '<'){ + if((collection = runestrdup(r)) != nil) + ncollection += runestrlen(r); + }else + /* use < command to collect text */ + runpipe(t, '<', r+1, nr-1, Collecting); return collection; }