fixes a critical GC safety inference bug (#10615)

* fixes a critical GC safety inference bug
* make nimsuggest compile again
* make Nimble compile again
This commit is contained in:
Andreas Rumpf
2019-03-05 19:54:44 +01:00
committed by GitHub
parent aed8766e84
commit c86b1fbcac
7 changed files with 65 additions and 34 deletions

View File

@@ -67,7 +67,7 @@ proc attachToType(d: PDoc; p: PSym): PSym =
template declareClosures =
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.procvar.} =
msgKind: rst.MsgKind, arg: string) {.procvar, gcsafe.} =
# translate msg kind:
var k: TMsgKind
case msgKind
@@ -81,9 +81,10 @@ template declareClosures =
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
of mwUnsupportedField: k = warnFieldXNotSupported
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
{.gcsafe.}:
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.procvar.} =
proc docgenFindFile(s: string): string {.procvar, gcsafe.} =
result = options.findFile(conf, s).string
if result.len == 0:
result = getCurrentDir() / s

View File

@@ -324,14 +324,15 @@ proc log*(s: string) {.procvar.} =
f.writeLine(s)
close(f)
proc quit(conf: ConfigRef; msg: TMsgKind) =
proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} =
if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
if stackTraceAvailable() and isNil(conf.writelnHook):
writeStackTrace()
else:
styledMsgWriteln(fgRed, "No stack traceback available\n" &
"To create a stacktrace, rerun compilation with ./koch temp " &
conf.command & " <file>")
{.gcsafe.}:
if stackTraceAvailable() and isNil(conf.writelnHook):
writeStackTrace()
else:
styledMsgWriteln(fgRed, "No stack traceback available\n" &
"To create a stacktrace, rerun compilation with ./koch temp " &
conf.command & " <file>")
quit 1
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =

View File

@@ -249,9 +249,9 @@ type
suggestVersion*: int
suggestMaxResults*: int
lastLineInfo*: TLineInfo
writelnHook*: proc (output: string) {.closure.}
writelnHook*: proc (output: string) {.closure.} # cannot make this gcsafe yet because of Nimble
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
severity: Severity) {.closure.}
severity: Severity) {.closure, gcsafe.}
cppCustomNamespace*: string
proc hcrOn*(conf: ConfigRef): bool = return optHotCodeReloading in conf.globalOptions

View File

@@ -82,12 +82,13 @@ proc newRope(data: string = ""): Rope =
result.L = -len(data)
result.data = data
var
cache: array[0..2048*2 - 1, Rope] # XXX Global here!
when not compileOption("threads"):
var
cache: array[0..2048*2 - 1, Rope]
proc resetRopeCache* =
for i in low(cache)..high(cache):
cache[i] = nil
proc resetRopeCache* =
for i in low(cache)..high(cache):
cache[i] = nil
proc ropeInvariant(r: Rope): bool =
if r == nil:
@@ -107,13 +108,16 @@ var gCacheMisses* = 0
var gCacheIntTries* = 0
proc insertInCache(s: string): Rope =
inc gCacheTries
var h = hash(s) and high(cache)
result = cache[h]
if isNil(result) or result.data != s:
inc gCacheMisses
when declared(cache):
inc gCacheTries
var h = hash(s) and high(cache)
result = cache[h]
if isNil(result) or result.data != s:
inc gCacheMisses
result = newRope(s)
cache[h] = result
else:
result = newRope(s)
cache[h] = result
proc rope*(s: string): Rope =
## Converts a string to a rope.

View File

@@ -721,6 +721,17 @@ proc cstringCheck(tracked: PEffects; n: PNode) =
message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
proc track(tracked: PEffects, n: PNode) =
template gcsafeAndSideeffectCheck() =
if notGcSafe(op) and not importedFromC(a):
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
markGcUnsafe(tracked, a)
if tfNoSideEffect notin op.flags and not importedFromC(a):
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
markSideEffect(tracked, a)
case n.kind
of nkSym:
useVar(tracked, n)
@@ -764,18 +775,11 @@ proc track(tracked: PEffects, n: PNode) =
propagateEffects(tracked, n, a.sym)
elif isIndirectCall(a, tracked.owner):
assumeTheWorst(tracked, n, op)
gcsafeAndSideeffectCheck()
else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
if notGcSafe(op) and not importedFromC(a):
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
markGcUnsafe(tracked, a)
if tfNoSideEffect notin op.flags and not importedFromC(a):
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
markSideEffect(tracked, a)
gcsafeAndSideeffectCheck()
if a.kind != nkSym or a.sym.magic != mNBindSym:
for i in 1 ..< len(n): trackOperand(tracked, n.sons[i], paramType(op, i), a)
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:

View File

@@ -45,8 +45,8 @@ type
mwUnsupportedField
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
arg: string) {.closure.} ## what to do in case of an error
FindFileHandler* = proc (filename: string): string {.closure.}
arg: string) {.closure, gcsafe.} ## what to do in case of an error
FindFileHandler* = proc (filename: string): string {.closure, gcsafe.}
const
messages: array[MsgKind, string] = [

View File

@@ -0,0 +1,21 @@
discard """
errormsg: "'myproc' is not GC-safe as it accesses 'global_proc' which is a global using GC'ed memory"
line: 12
cmd: "nim $target --hints:on --threads:on $options $file"
"""
var useGcMem = "string here"
var global_proc: proc(a: string) {.nimcall.} = proc (a: string) =
echo useGcMem
proc myproc(i: int) {.gcsafe.} =
when false:
if global_proc != nil:
echo "a"
if isNil(global_proc):
return
global_proc("ho")
myproc(0)