lib9/fmt: avoid racy access to installed fmt formats

This commit is contained in:
Russ Cox 2020-01-13 11:41:37 -05:00
parent d96e9e5dc3
commit 7ba9f9467d
4 changed files with 55 additions and 22 deletions

View file

@ -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)
@ -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++)
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){
__fmtinstall(p->c, p->fmt);
__fmtunlock();
__fmtwunlock();
return p->fmt;
}
__fmtunlock();
}
__fmtinstall(kp->c, kp->fmt);
__fmtwunlock();
return kp->fmt;
}
}
return __badfmt;
}

View file

@ -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);

View file

@ -5,11 +5,21 @@
#include "fmtdef.h"
void
__fmtlock(void)
__fmtrlock(void)
{
}
void
__fmtunlock(void)
__fmtrunlock(void)
{
}
void
__fmtwlock(void)
{
}
void
__fmtwunlock(void)
{
}

View file

@ -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);
}