diff options
| author | Russ Cox <rsc@swtch.com> | 2020-01-13 11:41:37 -0500 |
|---|---|---|
| committer | Russ Cox <rsc@swtch.com> | 2020-01-13 11:42:24 -0500 |
| commit | 7ba9f9467d95fa8d05bb04d36fd4c602e497f529 (patch) | |
| tree | 54f201e17fcc92cc2ccf2bfa3177e6d9bb5f8c6d /src/lib9/fmt/fmt.c | |
| parent | d96e9e5dc39a356febed132703e46bf73bac6850 (diff) | |
| download | plan9port-7ba9f9467d95fa8d05bb04d36fd4c602e497f529.tar.gz plan9port-7ba9f9467d95fa8d05bb04d36fd4c602e497f529.zip | |
lib9/fmt: avoid racy access to installed fmt formats
Diffstat (limited to 'src/lib9/fmt/fmt.c')
| -rw-r--r-- | src/lib9/fmt/fmt.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c index 66093fd0..9c3f45d3 100644 --- a/src/lib9/fmt/fmt.c +++ b/src/lib9/fmt/fmt.c @@ -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++) - 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; } |
