URI: 
       tlib9/fmt: avoid racy access to installed fmt formats - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 7ba9f9467d95fa8d05bb04d36fd4c602e497f529
   DIR parent d96e9e5dc39a356febed132703e46bf73bac6850
  HTML Author: Russ Cox <rsc@swtch.com>
       Date:   Mon, 13 Jan 2020 11:41:37 -0500
       
       lib9/fmt: avoid racy access to installed fmt formats
       
       Diffstat:
         M src/lib9/fmt/fmt.c                  |      35 +++++++++++++++++++------------
         M src/lib9/fmt/fmtdef.h               |       6 ++++--
         M src/lib9/fmt/fmtlock.c              |      14 ++++++++++++--
         M src/lib9/fmtlock2.c                 |      22 +++++++++++++++++-----
       
       4 files changed, 55 insertions(+), 22 deletions(-)
       ---
   DIR diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
       t@@ -72,7 +72,7 @@ static Convfmt knownfmt[] = {
        int        (*fmtdoquote)(int);
        
        /*
       - * __fmtlock() must be set
       + * __fmtwlock() must be set
         */
        static int
        __fmtinstall(int c, Fmts f)
       t@@ -106,34 +106,43 @@ fmtinstall(int c, int (*f)(Fmt*))
        {
                int ret;
        
       -        __fmtlock();
       +        __fmtwlock();
                ret = __fmtinstall(c, f);
       -        __fmtunlock();
       +        __fmtwunlock();
                return ret;
        }
        
        static Fmts
        fmtfmt(int c)
        {
       -        Convfmt *p, *ep;
       +        Convfmt *p, *ep, *kp;
        
       +        /* conflict-free check - common case */
       +        __fmtrlock();
                ep = &fmtalloc.fmt[fmtalloc.nfmt];
                for(p=fmtalloc.fmt; p<ep; p++)
                        if(p->c == c){
       -                        while(p->fmt == nil)        /* loop until value is updated */
       -                                ;
       +                        __fmtrunlock();
                                return p->fmt;
                        }
       +        __fmtrunlock();
        
                /* is this a predefined format char? */
       -        __fmtlock();
       -        for(p=knownfmt; p->c; p++)
       -                if(p->c == c){
       -                        __fmtinstall(p->c, p->fmt);
       -                        __fmtunlock();
       -                        return p->fmt;
       +        for(kp=knownfmt; kp->c; kp++){
       +                if(kp->c == c){
       +                        __fmtwlock();
       +                        /* double-check fmtinstall didn't happen */
       +                        for(p=fmtalloc.fmt; p<ep; p++){
       +                                if(p->c == c){
       +                                        __fmtwunlock();
       +                                        return p->fmt;
       +                                }
       +                        }
       +                        __fmtinstall(kp->c, kp->fmt);
       +                        __fmtwunlock();
       +                        return kp->fmt;
                        }
       -        __fmtunlock();
       +        }
        
                return __badfmt;
        }
   DIR diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
       t@@ -33,11 +33,13 @@ int          __fmtFdFlush(Fmt *f);
        int          __fmtcpy(Fmt *f, const void *vm, int n, int sz);
        void*        __fmtdispatch(Fmt *f, void *fmt, int isrunes);
        void *       __fmtflush(Fmt *f, void *t, int len);
       -void         __fmtlock(void);
        int          __fmtpad(Fmt *f, int n);
        double       __fmtpow10(int n);
        int          __fmtrcpy(Fmt *f, const void *vm, int n);
       -void         __fmtunlock(void);
       +void         __fmtrlock(void);
       +void         __fmtrunlock(void);
       +void         __fmtwlock(void);
       +void         __fmtwunlock(void);
        int          __ifmt(Fmt *f);
        int          __isInf(double d, int sign);
        int          __isNaN(double d);
   DIR diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
       t@@ -5,11 +5,21 @@
        #include "fmtdef.h"
        
        void
       -__fmtlock(void)
       +__fmtrlock(void)
        {
        }
        
        void
       -__fmtunlock(void)
       +__fmtrunlock(void)
       +{
       +}
       +
       +void
       +__fmtwlock(void)
       +{
       +}
       +
       +void
       +__fmtwunlock(void)
        {
        }
   DIR diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
       t@@ -1,16 +1,28 @@
        #include <u.h>
        #include <libc.h>
        
       -static Lock fmtlock;
       +static RWLock fmtlock;
        
        void
       -__fmtlock(void)
       +__fmtrlock(void)
        {
       -        lock(&fmtlock);
       +        rlock(&fmtlock);
        }
        
        void
       -__fmtunlock(void)
       +__fmtrunlock(void)
        {
       -        unlock(&fmtlock);
       +        runlock(&fmtlock);
       +}
       +
       +void
       +__fmtwlock(void)
       +{
       +        wlock(&fmtlock);
       +}
       +
       +void
       +__fmtwunlock(void)
       +{
       +        wunlock(&fmtlock);
        }