From 94038545bec1bffa9bf045be8a5e52b79e9f217c Mon Sep 17 00:00:00 2001 From: GULPF Date: Wed, 31 Jan 2018 16:29:42 +0100 Subject: [PATCH 1/8] Fixes codegen bug with literal negative zero, fixes #7079 (#7158) * Fixes #7079 * Fix handling of neg zero during constant folding --- compiler/jsgen.nim | 16 +++++++++++----- compiler/rodutils.nim | 16 ++++++++++------ compiler/semfold.nim | 1 + tests/ccgbugs/t7079.nim | 9 +++++++++ 4 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 tests/ccgbugs/t7079.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 6f40e70318..75880a15ab 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2284,11 +2284,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = r.kind = resExpr of nkFloatLit..nkFloat64Lit: let f = n.floatVal - if f != f: r.res = rope"NaN" - elif f == 0.0: r.res = rope"0.0" - elif f == 0.5 * f: - if f > 0.0: r.res = rope"Infinity" - else: r.res = rope"-Infinity" + case classify(f) + of fcNaN: + r.res = rope"NaN" + of fcNegZero: + r.res = rope"-0.0" + of fcZero: + r.res = rope"0.0" + of fcInf: + r.res = rope"Infinity" + of fcNegInf: + r.res = rope"-Infinity" else: r.res = rope(f.toStrMaxPrecision) r.kind = resExpr of nkCallKinds: diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 0456e93490..0d9c7112f4 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -8,18 +8,22 @@ # ## Serialization utilities for the compiler. -import strutils +import strutils, math proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "", nodecl, varargs.} proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = - if f != f: + case classify(f) + of fcNaN: result = "NAN" - elif f == 0.0: + of fcNegZero: + result = "-0.0" & literalPostfix + of fcZero: result = "0.0" & literalPostfix - elif f == 0.5 * f: - if f > 0.0: result = "INF" - else: result = "-INF" + of fcInf: + result = "INF" + of fcNegInf: + result = "-INF" else: when defined(nimNoArrayToCstringConversion): result = newString(81) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 55cdc334c7..59c55010f1 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -225,6 +225,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mDivF64: if getFloat(b) == 0.0: if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n) + elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n) else: result = newFloatNodeT(Inf, n) else: result = newFloatNodeT(getFloat(a) / getFloat(b), n) diff --git a/tests/ccgbugs/t7079.nim b/tests/ccgbugs/t7079.nim new file mode 100644 index 0000000000..bfa1b77a6b --- /dev/null +++ b/tests/ccgbugs/t7079.nim @@ -0,0 +1,9 @@ +discard """ + action: run + targets: '''c js''' +""" + +import math +let x = -0.0 +doAssert classify(x) == fcNegZero +doAssert classify(1 / -0.0) == fcNegInf \ No newline at end of file From 8d8df5807b4641410fb04a0fc2199f965f450909 Mon Sep 17 00:00:00 2001 From: pqflx3 Date: Wed, 31 Jan 2018 10:38:37 -0500 Subject: [PATCH 2/8] Fixes #7121 (#7148) * Replace ftell and fseek with (windows) _ftelli64, _fseeki64 and (posix) ftello, fseeko * disable large file test --- lib/system/sysio.nim | 22 ++++++++++++++-------- tests/system/io.nim | 25 ++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index f638b299ce..71cbb1c21b 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -47,10 +47,16 @@ when not declared(c_fwrite): # C routine that is used here: proc c_fread(buf: pointer, size, n: csize, f: File): csize {. importc: "fread", header: "", tags: [ReadIOEffect].} -proc c_fseek(f: File, offset: clong, whence: cint): cint {. - importc: "fseek", header: "", tags: [].} -proc c_ftell(f: File): clong {. - importc: "ftell", header: "", tags: [].} +when defined(windows): + proc c_fseek(f: File, offset: int64, whence: cint): cint {. + importc: "_fseeki64", header: "", tags: [].} + proc c_ftell(f: File): int64 {. + importc: "_ftelli64", header: "", tags: [].} +else: + proc c_fseek(f: File, offset: int64, whence: cint): cint {. + importc: "fseeko", header: "", tags: [].} + proc c_ftell(f: File): int64 {. + importc: "ftello", header: "", tags: [].} proc c_ferror(f: File): cint {. importc: "ferror", header: "", tags: [].} proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {. @@ -210,12 +216,12 @@ proc readAllBuffer(file: File): string = result.add(buffer) break -proc rawFileSize(file: File): int = +proc rawFileSize(file: File): int64 = # this does not raise an error opposed to `getFileSize` var oldPos = c_ftell(file) discard c_fseek(file, 0, 2) # seek the end of the file result = c_ftell(file) - discard c_fseek(file, clong(oldPos), 0) + discard c_fseek(file, oldPos, 0) proc endOfFile(f: File): bool = var c = c_fgetc(f) @@ -223,7 +229,7 @@ proc endOfFile(f: File): bool = return c < 0'i32 #result = c_feof(f) != 0 -proc readAllFile(file: File, len: int): string = +proc readAllFile(file: File, len: int64): string = # We acquire the filesize beforehand and hope it doesn't change. # Speeds things up. result = newString(len) @@ -363,7 +369,7 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool = result = f != nil proc setFilePos(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) = - if c_fseek(f, clong(pos), cint(relativeTo)) != 0: + if c_fseek(f, pos, cint(relativeTo)) != 0: raiseEIO("cannot set file position") proc getFilePos(f: File): int64 = diff --git a/tests/system/io.nim b/tests/system/io.nim index b0ccfda9f6..3d4df806bd 100644 --- a/tests/system/io.nim +++ b/tests/system/io.nim @@ -1,5 +1,5 @@ import - unittest, osproc, streams, os + unittest, osproc, streams, os, strformat const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." const TEST_FILE = "tests/testdata/string.txt" @@ -23,3 +23,26 @@ suite "io": test "file": check: readFile(TEST_FILE) == STRING_DATA + + +proc verifyFileSize(sz: int64) = + # issue 7121, large file size (2-4GB and >4Gb) + const fn = "tmpfile112358" + let size_in_mb = sz div 1_000_000 + + when defined(windows): + discard execProcess(&"fsutil file createnew {fn} {sz}" ) + else: + discard execProcess(&"dd if=/dev/zero of={fn} bs=1000000 count={size_in_mb}") + + doAssert os.getFileSize(fn) == sz # Verify OS filesize by string + + var f = open(fn) + doAssert f.getFileSize() == sz # Verify file handle filesize + f.close() + + os.removeFile(fn) + +#disable tests for automatic testers +#for s in [50_000_000'i64, 3_000_000_000, 5_000_000_000]: +# verifyFileSize(s) From 60c7bbc8b7e75951b952a34051a8445592a68fc4 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 31 Jan 2018 18:39:01 +0300 Subject: [PATCH 3/8] Jump to definition on import will open the imported module (#7155) --- compiler/importer.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/importer.nim b/compiler/importer.nim index 46d675b275..3d7f624642 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -11,7 +11,7 @@ import intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, - semdata, passes, renderer, modulepaths + semdata, passes, renderer, modulepaths, sigmatch proc evalImport*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode @@ -149,7 +149,7 @@ proc myImportModule(c: PContext, n: PNode): PSym = localError(n.info, errGenerated, "A module cannot import itself") if sfDeprecated in result.flags: message(n.info, warnDeprecated, result.name.s) - #suggestSym(n.info, result, false) + suggestSym(n.info, result, c.graph.usageSym, false) proc impMod(c: PContext; it: PNode) = let m = myImportModule(c, it) From 90c1edff8bad05dc21c0c5a79fc026cac2b5fe4c Mon Sep 17 00:00:00 2001 From: konqoro Date: Thu, 1 Feb 2018 15:02:32 +0200 Subject: [PATCH 4/8] Fix the names of the float checks pragmas. (#7170) --- doc/manual/types.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual/types.txt b/doc/manual/types.txt index 1477995dda..8a90dee050 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -181,11 +181,11 @@ Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:, and `FloatInexactError`:idx:. These exceptions inherit from the `FloatingPointError`:idx: base class. -Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control +Nim provides the pragmas `nanChecks`:idx: and `infChecks`:idx: to control whether the IEEE exceptions are ignored or trap a Nim exception: .. code-block:: nim - {.NanChecks: on, InfChecks: on.} + {.nanChecks: on, infChecks: on.} var a = 1.0 var b = 0.0 echo b / b # raises FloatInvalidOpError @@ -195,7 +195,7 @@ In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError`` are never raised. ``FloatOverflowError`` is raised instead of ``FloatDivByZeroError``. There is also a `floatChecks`:idx: pragma that is a short-cut for the -combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are +combination of ``nanChecks`` and ``infChecks`` pragmas. ``floatChecks`` are turned off as default. The only operations that are affected by the ``floatChecks`` pragma are From 5460bd2764db46048b9a3ecdd1d17a20a4b48b79 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 1 Feb 2018 17:34:37 +0000 Subject: [PATCH 5/8] Small performance improvement in sempass2 (#7168) --- compiler/sempass2.nim | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e560c18c85..25525d4123 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -593,17 +593,14 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = notNilCheck(tracked, n, paramType) proc breaksBlock(n: PNode): bool = - case n.kind - of nkStmtList, nkStmtListExpr: - for c in n: - if breaksBlock(c): return true - of nkBreakStmt, nkReturnStmt, nkRaiseStmt: - return true - of nkCallKinds: - if n.sons[0].kind == nkSym and sfNoReturn in n.sons[0].sym.flags: - return true - else: - discard + # sematic check doesn't allow statements after raise, break, return or + # call to noreturn proc, so it is safe to check just the last statements + var it = n + while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: + it = it.lastSon + + result = it.kind in {nkBreakStmt, nkReturnStmt, nkRaiseStmt} or + it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags proc trackCase(tracked: PEffects, n: PNode) = track(tracked, n.sons[0]) From c671356d51488c96b4749a4d109b00d924e1f739 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Feb 2018 08:07:31 +0100 Subject: [PATCH 6/8] manual: do not mention the VTable types which are not implemented yet --- doc/manual/generics.txt | 89 +++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt index 1ba62bb5ca..09fecbd959 100644 --- a/doc/manual/generics.txt +++ b/doc/manual/generics.txt @@ -314,7 +314,7 @@ The concept types can be parametric just like the regular generic types: .. code-block:: nim ### matrixalgo.nim - + import typetraits type @@ -360,7 +360,7 @@ The concept types can be parametric just like the regular generic types: template Rows*(M: type Matrix): expr = M.M template Cols*(M: type Matrix): expr = M.N template ValueType*(M: type Matrix): typedesc = M.T - + ------------- ### usage.nim @@ -582,60 +582,61 @@ the concept body: proc log(format: static[string], varargs[distinct StringRef]) -VTable types ------------- +.. + VTable types + ------------ -Concepts allow Nim to define a great number of algorithms, using only -static polymorphism and without erasing any type information or sacrificing -any execution speed. But when polymorphic collections of objects are required, -the user must use one of the provided type erasure techniques - either common -base types or VTable types. + Concepts allow Nim to define a great number of algorithms, using only + static polymorphism and without erasing any type information or sacrificing + any execution speed. But when polymorphic collections of objects are required, + the user must use one of the provided type erasure techniques - either common + base types or VTable types. -VTable types are represented as "fat pointers" storing a reference to an -object together with a reference to a table of procs implementing a set of -required operations (the so called vtable). + VTable types are represented as "fat pointers" storing a reference to an + object together with a reference to a table of procs implementing a set of + required operations (the so called vtable). -In contrast to other programming languages, the vtable in Nim is stored -externally to the object, allowing you to create multiple different vtable -views for the same object. Thus, the polymorphism in Nim is unbounded - -any type can implement an unlimited number of protocols or interfaces not -originally envisioned by the type's author. + In contrast to other programming languages, the vtable in Nim is stored + externally to the object, allowing you to create multiple different vtable + views for the same object. Thus, the polymorphism in Nim is unbounded - + any type can implement an unlimited number of protocols or interfaces not + originally envisioned by the type's author. -Any concept type can be turned into a VTable type by using the ``vtref`` -or the ``vtptr`` compiler magics. Under the hood, these magics generate -a converter type class, which converts the regular instances of the matching -types to the corresponding VTable type. + Any concept type can be turned into a VTable type by using the ``vtref`` + or the ``vtptr`` compiler magics. Under the hood, these magics generate + a converter type class, which converts the regular instances of the matching + types to the corresponding VTable type. -.. code-block:: nim - type - IntEnumerable = vtref Enumerable[int] + .. code-block:: nim + type + IntEnumerable = vtref Enumerable[int] - MyObject = object - enumerables: seq[IntEnumerable] - streams: seq[OutputStream.vtref] + MyObject = object + enumerables: seq[IntEnumerable] + streams: seq[OutputStream.vtref] - proc addEnumerable(o: var MyObject, e: IntEnumerable) = - o.enumerables.add e + proc addEnumerable(o: var MyObject, e: IntEnumerable) = + o.enumerables.add e - proc addStream(o: var MyObject, e: OutputStream.vtref) = - o.streams.add e + proc addStream(o: var MyObject, e: OutputStream.vtref) = + o.streams.add e -The procs that will be included in the vtable are derived from the concept -body and include all proc calls for which all param types were specified as -concrete types. All such calls should include exactly one param of the type -matched against the concept (not necessarily in the first position), which -will be considered the value bound to the vtable. + The procs that will be included in the vtable are derived from the concept + body and include all proc calls for which all param types were specified as + concrete types. All such calls should include exactly one param of the type + matched against the concept (not necessarily in the first position), which + will be considered the value bound to the vtable. -Overloads will be created for all captured procs, accepting the vtable type -in the position of the captured underlying object. + Overloads will be created for all captured procs, accepting the vtable type + in the position of the captured underlying object. -Under these rules, it's possible to obtain a vtable type for a concept with -unbound type parameters or one instantiated with metatypes (type classes), -but it will include a smaller number of captured procs. A completely empty -vtable will be reported as an error. + Under these rules, it's possible to obtain a vtable type for a concept with + unbound type parameters or one instantiated with metatypes (type classes), + but it will include a smaller number of captured procs. A completely empty + vtable will be reported as an error. -The ``vtref`` magic produces types which can be bound to ``ref`` types and -the ``vtptr`` magic produced types bound to ``ptr`` types. + The ``vtref`` magic produces types which can be bound to ``ref`` types and + the ``vtptr`` magic produced types bound to ``ptr`` types. Symbol lookup in generics From 274fafb2df9d433f59e5729ebc05200eeeca4e45 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Feb 2018 13:12:30 +0100 Subject: [PATCH 7/8] fixes #6961 --- compiler/ast.nim | 2 +- compiler/cgen.nim | 2 +- compiler/extccomp.nim | 2 +- compiler/gorgeimpl.nim | 2 +- compiler/jsgen.nim | 2 +- compiler/modules.nim | 2 +- compiler/rodread.nim | 2 +- compiler/rodwrite.nim | 2 +- lib/pure/securehash.nim | 197 +------------------------------------- lib/pure/sha1.nim | 195 +++++++++++++++++++++++++++++++++++++ lib/system.nim | 1 - tools/niminst/niminst.nim | 2 +- web/website.ini | 2 +- 13 files changed, 209 insertions(+), 204 deletions(-) create mode 100644 lib/pure/sha1.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 5c70bda186..a19dbf7de1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,7 @@ # abstract syntax tree + symbol table import - msgs, hashes, nversion, options, strutils, securehash, ropes, idents, + msgs, hashes, nversion, options, strutils, sha1, ropes, idents, intsets, idgen type diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 12e640d96a..6051f28049 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -11,7 +11,7 @@ import ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, - nversion, nimsets, msgs, securehash, bitsets, idents, types, + nversion, nimsets, msgs, sha1, bitsets, idents, types, ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, semparallel, tables, sets, ndi diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 62990593d0..3a6fcde5aa 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -14,7 +14,7 @@ import ropes, os, strutils, osproc, platform, condsyms, options, msgs, - securehash, streams + sha1, streams #from debuginfo import writeDebugInfo diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 2c51752cd6..9cc6eb2ba0 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -9,7 +9,7 @@ ## Module that implements ``gorge`` for the compiler. -import msgs, securehash, os, osproc, streams, strutils, options +import msgs, sha1, os, osproc, streams, strutils, options proc readOutput(p: Process): (string, int) = result[0] = "" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 75880a15ab..3288241d91 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -31,7 +31,7 @@ implements the required case distinction. import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, - nversion, nimsets, msgs, securehash, bitsets, idents, types, os, + nversion, nimsets, msgs, sha1, bitsets, idents, types, os, times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, intsets, cgmeth, lowerings diff --git a/compiler/modules.nim b/compiler/modules.nim index 4763ac79bc..e94c5c1622 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -10,7 +10,7 @@ ## Implements the module handling, including the caching of modules. import - ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options, + ast, astalgo, magicsys, sha1, rodread, msgs, cgendata, sigmatch, options, idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs when false: diff --git a/compiler/rodread.nim b/compiler/rodread.nim index dfa8fc52ba..5abac1d794 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -90,7 +90,7 @@ import os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, - ropes, idents, securehash, idgen, types, rodutils, memfiles, tables + ropes, idents, sha1, idgen, types, rodutils, memfiles, tables type TReasonForRecompile* = enum ## all the reasons that can trigger recompilation diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 9aed33ec97..24d897fb10 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -13,7 +13,7 @@ import intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform, - condsyms, ropes, idents, securehash, rodread, passes, idgen, + condsyms, ropes, idents, sha1, rodread, passes, idgen, rodutils, modulepaths from modulegraphs import ModuleGraph diff --git a/lib/pure/securehash.nim b/lib/pure/securehash.nim index 57c1f3631c..06da80e4c8 100644 --- a/lib/pure/securehash.nim +++ b/lib/pure/securehash.nim @@ -1,195 +1,6 @@ -# -# -# The Nim Compiler -# (c) Copyright 2015 Nim Contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import strutils - -const Sha1DigestSize = 20 - -type - Sha1Digest = array[0 .. Sha1DigestSize-1, uint8] - SecureHash* = distinct Sha1Digest - -# Copyright (c) 2011, Micael Hildenborg -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Micael Hildenborg nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Ported to Nim by Erik O'Leary - -type - Sha1State* = array[0 .. 5-1, uint32] - Sha1Buffer = array[0 .. 80-1, uint32] - -template clearBuffer(w: Sha1Buffer, len = 16) = - zeroMem(addr(w), len * sizeof(uint32)) - -proc init*(result: var Sha1State) = - result[0] = 0x67452301'u32 - result[1] = 0xefcdab89'u32 - result[2] = 0x98badcfe'u32 - result[3] = 0x10325476'u32 - result[4] = 0xc3d2e1f0'u32 - -proc innerHash(state: var Sha1State, w: var Sha1Buffer) = - var - a = state[0] - b = state[1] - c = state[2] - d = state[3] - e = state[4] - - var round = 0 - - template rot(value, bits: uint32): uint32 = - (value shl bits) or (value shr (32 - bits)) - - template sha1(fun, val: uint32) = - let t = rot(a, 5) + fun + e + val + w[round] - e = d - d = c - c = rot(b, 30) - b = a - a = t - - template process(body: untyped) = - w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1) - body - inc(round) - - template wrap(dest, value: untyped) = - let v = dest + value - dest = v - - while round < 16: - sha1((b and c) or (not b and d), 0x5a827999'u32) - inc(round) - - while round < 20: - process: - sha1((b and c) or (not b and d), 0x5a827999'u32) - - while round < 40: - process: - sha1(b xor c xor d, 0x6ed9eba1'u32) - - while round < 60: - process: - sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32) - - while round < 80: - process: - sha1(b xor c xor d, 0xca62c1d6'u32) - - wrap state[0], a - wrap state[1], b - wrap state[2], c - wrap state[3], d - wrap state[4], e - -proc sha1(src: cstring; len: int): Sha1Digest = - #Initialize state - var state: Sha1State - init(state) - - #Create w buffer - var w: Sha1Buffer - - #Loop through all complete 64byte blocks. - let byteLen = len - let endOfFullBlocks = byteLen - 64 - var endCurrentBlock = 0 - var currentBlock = 0 - - while currentBlock <= endOfFullBlocks: - endCurrentBlock = currentBlock + 64 - - var i = 0 - while currentBlock < endCurrentBlock: - w[i] = uint32(src[currentBlock+3]) or - uint32(src[currentBlock+2]) shl 8'u32 or - uint32(src[currentBlock+1]) shl 16'u32 or - uint32(src[currentBlock]) shl 24'u32 - currentBlock += 4 - inc(i) - - innerHash(state, w) - - #Handle last and not full 64 byte block if existing - endCurrentBlock = byteLen - currentBlock - clearBuffer(w) - var lastBlockBytes = 0 - - while lastBlockBytes < endCurrentBlock: - - var value = uint32(src[lastBlockBytes + currentBlock]) shl - ((3'u32 - uint32(lastBlockBytes and 3)) shl 3) - - w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value - inc(lastBlockBytes) - - w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or ( - 0x80'u32 shl ((3'u32 - uint32(lastBlockBytes and 3)) shl 3) - ) - - if endCurrentBlock >= 56: - innerHash(state, w) - clearBuffer(w) - - w[15] = uint32(byteLen) shl 3 - innerHash(state, w) - - # Store hash in result pointer, and make sure we get in in the correct order - # on both endian models. - for i in 0 .. Sha1DigestSize-1: - result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255) - -proc sha1(src: string): Sha1Digest = - ## Calculate SHA1 from input string - sha1(src, src.len) - -proc secureHash*(str: string): SecureHash = SecureHash(sha1(str)) -proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename)) -proc `$`*(self: SecureHash): string = - result = "" - for v in Sha1Digest(self): - result.add(toHex(int(v), 2)) - -proc parseSecureHash*(hash: string): SecureHash = - for i in 0 ..< Sha1DigestSize: - Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1])) - -proc `==`*(a, b: SecureHash): bool = - # Not a constant-time comparison, but that's acceptable in this context - Sha1Digest(a) == Sha1Digest(b) -when isMainModule: - let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]") - doAssert hash1 == hash1 - doAssert parseSecureHash($hash1) == hash1 +## This module is a deprecated alias for the ``sha1`` module. +{.deprecated.} + +include sha1 diff --git a/lib/pure/sha1.nim b/lib/pure/sha1.nim new file mode 100644 index 0000000000..b18095ff61 --- /dev/null +++ b/lib/pure/sha1.nim @@ -0,0 +1,195 @@ +# +# +# The Nim Compiler +# (c) Copyright 2015 Nim Contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import strutils + +const Sha1DigestSize = 20 + +type + Sha1Digest = array[0 .. Sha1DigestSize-1, uint8] + SecureHash* = distinct Sha1Digest + +# Copyright (c) 2011, Micael Hildenborg +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Micael Hildenborg nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Ported to Nim by Erik O'Leary + +type + Sha1State* = array[0 .. 5-1, uint32] + Sha1Buffer = array[0 .. 80-1, uint32] + +template clearBuffer(w: Sha1Buffer, len = 16) = + zeroMem(addr(w), len * sizeof(uint32)) + +proc init*(result: var Sha1State) = + result[0] = 0x67452301'u32 + result[1] = 0xefcdab89'u32 + result[2] = 0x98badcfe'u32 + result[3] = 0x10325476'u32 + result[4] = 0xc3d2e1f0'u32 + +proc innerHash(state: var Sha1State, w: var Sha1Buffer) = + var + a = state[0] + b = state[1] + c = state[2] + d = state[3] + e = state[4] + + var round = 0 + + template rot(value, bits: uint32): uint32 = + (value shl bits) or (value shr (32u32 - bits)) + + template sha1(fun, val: uint32) = + let t = rot(a, 5) + fun + e + val + w[round] + e = d + d = c + c = rot(b, 30) + b = a + a = t + + template process(body: untyped) = + w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1) + body + inc(round) + + template wrap(dest, value: untyped) = + let v = dest + value + dest = v + + while round < 16: + sha1((b and c) or (not b and d), 0x5a827999'u32) + inc(round) + + while round < 20: + process: + sha1((b and c) or (not b and d), 0x5a827999'u32) + + while round < 40: + process: + sha1(b xor c xor d, 0x6ed9eba1'u32) + + while round < 60: + process: + sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32) + + while round < 80: + process: + sha1(b xor c xor d, 0xca62c1d6'u32) + + wrap state[0], a + wrap state[1], b + wrap state[2], c + wrap state[3], d + wrap state[4], e + +proc sha1(src: cstring; len: int): Sha1Digest = + #Initialize state + var state: Sha1State + init(state) + + #Create w buffer + var w: Sha1Buffer + + #Loop through all complete 64byte blocks. + let byteLen = len + let endOfFullBlocks = byteLen - 64 + var endCurrentBlock = 0 + var currentBlock = 0 + + while currentBlock <= endOfFullBlocks: + endCurrentBlock = currentBlock + 64 + + var i = 0 + while currentBlock < endCurrentBlock: + w[i] = uint32(src[currentBlock+3]) or + uint32(src[currentBlock+2]) shl 8'u32 or + uint32(src[currentBlock+1]) shl 16'u32 or + uint32(src[currentBlock]) shl 24'u32 + currentBlock += 4 + inc(i) + + innerHash(state, w) + + #Handle last and not full 64 byte block if existing + endCurrentBlock = byteLen - currentBlock + clearBuffer(w) + var lastBlockBytes = 0 + + while lastBlockBytes < endCurrentBlock: + + var value = uint32(src[lastBlockBytes + currentBlock]) shl + ((3'u32 - uint32(lastBlockBytes and 3)) shl 3) + + w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value + inc(lastBlockBytes) + + w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or ( + 0x80'u32 shl ((3'u32 - uint32(lastBlockBytes and 3)) shl 3) + ) + + if endCurrentBlock >= 56: + innerHash(state, w) + clearBuffer(w) + + w[15] = uint32(byteLen) shl 3 + innerHash(state, w) + + # Store hash in result pointer, and make sure we get in in the correct order + # on both endian models. + for i in 0 .. Sha1DigestSize-1: + result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255) + +proc sha1(src: string): Sha1Digest = + ## Calculate SHA1 from input string + sha1(src, src.len) + +proc secureHash*(str: string): SecureHash = SecureHash(sha1(str)) +proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename)) +proc `$`*(self: SecureHash): string = + result = "" + for v in Sha1Digest(self): + result.add(toHex(int(v), 2)) + +proc parseSecureHash*(hash: string): SecureHash = + for i in 0 ..< Sha1DigestSize: + Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1])) + +proc `==`*(a, b: SecureHash): bool = + # Not a constant-time comparison, but that's acceptable in this context + Sha1Digest(a) == Sha1Digest(b) + + +when isMainModule: + let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]") + doAssert hash1 == hash1 + doAssert parseSecureHash($hash1) == hash1 diff --git a/lib/system.nim b/lib/system.nim index 079b06b489..63511f71c0 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3769,7 +3769,6 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = # by ``assert``. type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} - {.deprecated: [THide: Hide].} Hide(raiseAssert)(msg) template assert*(cond: bool, msg = "") = diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 9c15326b0a..c2fe79087e 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -15,7 +15,7 @@ when haveZipLib: import os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation, - securehash + sha1 const maxOS = 20 # max number of OSes diff --git a/web/website.ini b/web/website.ini index 273c3223d3..4420915aba 100644 --- a/web/website.ini +++ b/web/website.ini @@ -65,7 +65,7 @@ srcdoc2: "pure/asyncfile;pure/asyncftpclient;pure/lenientops" srcdoc2: "pure/md5;pure/rationals" srcdoc2: "posix/posix;pure/distros;pure/oswalkdir" srcdoc2: "pure/collections/heapqueue" -srcdoc2: "pure/fenv;pure/securehash;impure/rdstdin;pure/strformat" +srcdoc2: "pure/fenv;pure/sha1;impure/rdstdin;pure/strformat" srcdoc2: "pure/segfaults" srcdoc2: "pure/basic2d;pure/basic3d;pure/mersenne;pure/coro;pure/httpcore" srcdoc2: "pure/bitops;pure/nimtracker;pure/punycode;pure/volatile;js/asyncjs" From 4f9ae61695bc7a03b15a8d26ee1e702582db76af Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 2 Feb 2018 17:34:54 +0100 Subject: [PATCH 8/8] fixes #6939 --- lib/pure/os.nim | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index a5db4ed22a..f8936f549a 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -139,10 +139,15 @@ proc findExe*(exe: string, followSymlinks: bool = true; ## is added the `ExeExts <#ExeExts>`_ file extensions if it has none. ## If the system supports symlinks it also resolves them until it ## meets the actual file. This behavior can be disabled if desired. - for ext in extensions: - result = addFileExt(exe, ext) - if existsFile(result): return - var path = string(getEnv("PATH")) + template checkCurrentDir() = + for ext in extensions: + result = addFileExt(exe, ext) + if existsFile(result): return + when defined(posix): + if '/' in exe: checkCurrentDir() + else: + checkCurrentDir() + let path = string(getEnv("PATH")) for candidate in split(path, PathSep): when defined(windows): var x = (if candidate[0] == '"' and candidate[^1] == '"': @@ -824,7 +829,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: iterator walkDirRec*(dir: string, yieldFilter = {pcFile}, followFilter = {pcDir}): string {.tags: [ReadDirEffect].} = - ## Recursively walks over the directory `dir` and yields for each file + ## Recursively walks over the directory `dir` and yields for each file ## or directory in `dir`. ## The full path for each file or directory is returned. ## **Warning**: