[Issue 16232] std.experimental.logger.core.sharedLog isn't thread-safe
via Digitalmars-d-bugs
digitalmars-d-bugs at puremagic.com
Fri Jul 14 09:02:46 PDT 2017
https://issues.dlang.org/show_bug.cgi?id=16232
ag0aep6g at gmail.com changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|RESOLVED |REOPENED
Resolution|FIXED |---
--- Comment #6 from ag0aep6g at gmail.com ---
(In reply to Robert Schadek from comment #3)
> I will add a comment to make that clear
Reopening. I think a comment isn't enough. sharedLog is marked as @safe, but it
effectively casts shared away, which isn't safe. It can lead to memory
corruption when shared data can be accessed as unshared.
I see two ways out:
1) Make sharedLog @system.
2) Return a shared Logger.
Lengthy example of @safe violation with custom Logger:
----
import std.experimental.logger.core: Logger, LogLevel, sharedLog;
class MyLogger : Logger
{
ulong* p;
this() @safe
{
super(LogLevel.all);
/* Allocate a ulong that disrespects cache line boundaries (64 bytes),
so that it won't be loaded/stored atomically. */
align(64) static struct S
{
align(1):
ubyte[60] off;
ulong x = 0;
}
auto s = new S;
this.p = &s.x;
assert((cast(size_t) p) % 64 == 60);
assert((cast(size_t) p) % s.x.sizeof == 4);
}
override void writeLogMsg(ref LogEntry payload) @safe { assert(false); }
/* never called */
}
MyLogger sharedMyLogger() @safe
{
Logger logger = sharedLog();
return cast(MyLogger) logger;
/* This is a simple downcast. Not casting away shared. */
}
enum n = 1_000_000;
/* Toggle *p between 0 and ulong.max (n times). */
void write(ulong* p) @safe
{
foreach (i; 0 .. n) *p = ~*p; /* non-atomic load and store */
}
/* Assert that *p is either 0 or ulong.max (n times). */
void read(ulong* p) @safe
{
import std.conv: to;
foreach (i; 0 .. n)
{
ulong val = *p; /* non-atomic load */
assert(val == 0 || val == ulong.max, val.to!string(16)); /* fails */
}
}
void main()
{
sharedLog = new MyLogger;
/* Read and write concurrently. `read` will see a partially written value.
I.e., memory corruption. */
import core.thread: Thread;
new Thread(() @safe { write(sharedMyLogger.p); }).start();
read(sharedMyLogger.p);
}
----
--
More information about the Digitalmars-d-bugs
mailing list