Skip to content

Commit

Permalink
use a full MD5 hash with no collision detection for proc names
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Nov 8, 2016
1 parent c0b8a79 commit 72af7e6
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 64 deletions.
62 changes: 33 additions & 29 deletions compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

# ------------------------- Name Mangling --------------------------------

import debuginfo, sighashes
import sighashes

proc isKeyword(w: PIdent): bool =
# Nim and C++ share some keywords
Expand All @@ -29,26 +29,29 @@ proc mangleField(name: PIdent): string =
# Mangling makes everything lowercase,
# but some identifiers are C keywords

proc hashOwner(s: PSym): SigHash =
var m = s
while m.kind != skModule: m = m.owner
let p = m.owner
assert p.kind == skPackage
result = gDebugInfo.register(p.name.s, m.name.s)
when false:
proc hashOwner(s: PSym): SigHash =
var m = s
while m.kind != skModule: m = m.owner
let p = m.owner
assert p.kind == skPackage
result = gDebugInfo.register(p.name.s, m.name.s)

proc idOrSig(m: BModule; s: PSym): BiggestInt =
proc idOrSig(m: BModule; s: PSym): Rope =
if s.kind in routineKinds and s.typ != nil and sfExported in s.flags and
s.typ.callConv != ccInline:
# signatures for exported routines are reliable enough to
# produce a unique name and this means produced C++ is more stable wrt
# Nim changes:
let h = hashType(s.typ, {considerParamNames})
if m.hashConflicts.containsOrIncl(cast[int](h)):
result = s.id
else:
result = BiggestInt(h)
when false:
let h = hashType(s.typ, {considerParamNames})
if m.hashConflicts.containsOrIncl(cast[int](h)):
result = s.id
else:
result = BiggestInt(h)
result = rope($hashProc(s))
else:
result = s.id
result = rope s.id

proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r
Expand Down Expand Up @@ -100,9 +103,9 @@ proc mangleName(m: BModule; s: PSym): Rope =
result.add "0"
else:
add(result, ~"_")
add(result, rope(m.idOrSig(s)))
add(result, ~"_")
add(result, rope(hashOwner(s).BiggestInt))
add(result, m.idOrSig(s))
#add(result, ~"_")
#add(result, rope(hashOwner(s).BiggestInt))
s.loc.r = result

proc typeName(typ: PType): Rope =
Expand All @@ -114,7 +117,7 @@ proc getTypeName(m: BModule; typ: PType): Rope =
result = typ.sym.loc.r
else:
if typ.loc.r == nil:
when true:
when false:
# doesn't work yet and would require bigger rewritings
let h = hashType(typ, {considerParamNames})# and 0x0fff_ffffu32
let sig =
Expand All @@ -125,8 +128,8 @@ proc getTypeName(m: BModule; typ: PType): Rope =
else:
let sig = BiggestInt typ.id
typ.loc.r = typ.typeName & sig.rope #& ("_" & m.module.name.s)
if typ.kind != tySet:
typ.loc.r.add "_" & m.module.name.s
#if typ.kind != tySet:
# typ.loc.r.add "_" & m.module.name.s
result = typ.loc.r
if result == nil: internalError("getTypeName: " & $typ.kind)

Expand Down Expand Up @@ -625,15 +628,16 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
else: internalError(t.sym.info, "getTypeDescAux: enum")
let owner = hashOwner(t.sym)
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
var vals: seq[(string, int)] = @[]
for i in countup(0, t.n.len - 1):
assert(t.n.sons[i].kind == nkSym)
let field = t.n.sons[i].sym
vals.add((field.name.s, field.position.int))
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
name: t.sym.name.s, values: vals))
when false:
let owner = hashOwner(t.sym)
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
var vals: seq[(string, int)] = @[]
for i in countup(0, t.n.len - 1):
assert(t.n.sons[i].kind == nkSym)
let field = t.n.sons[i].sym
vals.add((field.name.s, field.position.int))
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
name: t.sym.name.s, values: vals))
of tyProc:
result = getTypeName(m, t)
idTablePut(m.typeCache, t, result)
Expand Down
6 changes: 3 additions & 3 deletions compiler/debuginfo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
# distribution, for details about the copyright.
#

## The compiler can generate debuginfo to help debuggers in translating back from C/C++/JS code
## to Nim. The data structure has been designed to produce something useful with Nim's marshal
## module.
## The compiler can generate debuginfo to help debuggers in translating back
## from C/C++/JS code to Nim. The data structure has been designed to produce
## something useful with Nim's marshal module.

import sighashes

Expand Down
6 changes: 3 additions & 3 deletions compiler/extccomp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
securehash, streams

from debuginfo import writeDebugInfo
#from debuginfo import writeDebugInfo

type
TSystemCC* = enum
Expand Down Expand Up @@ -734,8 +734,8 @@ proc callCCompiler*(projectfile: string) =
if not noAbsolutePaths():
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
if optCDebug in gGlobalOptions:
writeDebugInfo(exefile.changeFileExt("ndb"))
#if optCDebug in gGlobalOptions:
# writeDebugInfo(exefile.changeFileExt("ndb"))
exefile = quoteShell(exefile)
let linkOptions = getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")
Expand Down
102 changes: 88 additions & 14 deletions compiler/sighashes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,63 @@

## Computes hash values for routine (proc, method etc) signatures.

import ast
import ast, md5
export md5.`==`

type
SigHash* = uint32 ## a hash good enough for a filename or a proc signature
when false:
type
SigHash* = uint32 ## a hash good enough for a filename or a proc signature

proc sdbmHash(hash: SigHash, c: char): SigHash {.inline.} =
return SigHash(c) + (hash shl 6) + (hash shl 16) - hash

template `&=`*(x: var SigHash, c: char) = x = sdbmHash(x, c)
template `&=`*(x: var SigHash, s: string) =
for c in s: x = sdbmHash(x, c)

else:
type
SigHash* = Md5Digest

const
cb64 = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9a",
"9b", "9c"]

proc sdbmHash(hash: SigHash, c: char): SigHash {.inline.} =
return SigHash(c) + (hash shl 6) + (hash shl 16) - hash
proc toBase64a(s: cstring, len: int): string =
## encodes `s` into base64 representation.
result = newStringOfCap(((len + 2) div 3) * 4)
var i = 0
while i < len - 2:
let a = ord(s[i])
let b = ord(s[i+1])
let c = ord(s[i+2])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result.add cb64[c and 0x3F]
inc(i, 3)
if i < len-1:
let a = ord(s[i])
let b = ord(s[i+1])
result.add cb64[a shr 2]
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result.add cb64[((b and 0x0F) shl 2)]
elif i < len:
let a = ord(s[i])
result.add cb64[a shr 2]
result.add cb64[(a and 3) shl 4]

template `&=`*(x: var SigHash, c: char) = x = sdbmHash(x, c)
template `&=`*(x: var SigHash, s: string) =
for c in s: x = sdbmHash(x, c)
proc `$`*(u: SigHash): string =
toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1)

proc hashSym(c: var SigHash, s: PSym) =
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
else:
Expand All @@ -31,9 +75,9 @@ proc hashSym(c: var SigHash, s: PSym) =
c &= "."
it = it.owner

proc hashTree(c: var SigHash, n: PNode) =
proc hashTree(c: var MD5Context, n: PNode) =
template lowlevel(v) =
for i in 0..<sizeof(v): c = sdbmHash(c, cast[cstring](unsafeAddr(v))[i])
md5Update(c, cast[cstring](unsafeAddr(v)), sizeof(v))

if n == nil:
c &= "\255"
Expand Down Expand Up @@ -63,7 +107,7 @@ type
ConsiderFlag* = enum
considerParamNames

proc hashType(c: var SigHash, t: PType; flags: set[ConsiderFlag]) =
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# modelled after 'typeToString'
if t == nil:
c &= "\254"
Expand Down Expand Up @@ -133,5 +177,35 @@ proc hashType(c: var SigHash, t: PType; flags: set[ConsiderFlag]) =
if tfNotNil in t.flags: c &= "not nil"

proc hashType*(t: PType; flags: set[ConsiderFlag]): SigHash =
result = 0
hashType result, t, flags
var c: MD5Context
md5Init c
hashType c, t, flags
md5Final c, result

proc hashProc*(s: PSym): SigHash =
var c: MD5Context
md5Init c
hashType c, s.typ, {considerParamNames}

var m = s
while m.kind != skModule: m = m.owner
let p = m.owner
assert p.kind == skPackage
c &= p.name.s
c &= "."
c &= m.name.s

md5Final c, result

proc hashOwner*(s: PSym): SigHash =
var c: MD5Context
md5Init c
var m = s
while m.kind != skModule: m = m.owner
let p = m.owner
assert p.kind == skPackage
c &= p.name.s
c &= "."
c &= m.name.s

md5Final c, result
15 changes: 0 additions & 15 deletions lib/pure/securehash.nim
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,6 @@ proc sha1(src: string): Sha1Digest =
## Calculate SHA1 from input string
sha1(src, src.len)

proc `!&`*(h: Hash, val: int): Hash {.inline.} =
## mixes a hash value `h` with `val` to produce a new hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)

proc `!$`*(h: Hash): Hash {.inline.} =
## finishes the computation of the hash value. This is
## only needed if you need to implement a hash proc for a new datatype.

proc
proc hashData*(data: pointer, size: int): Hash =


proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
proc `$`*(self: SecureHash): string =
Expand Down

0 comments on commit 72af7e6

Please sign in to comment.