-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add byte-array-to-string conversion to system module #14810
Comments
I agree with the general idea (common cases like this should not require a
|
This would be really useful. Ideally, it should be possible to get an immutable string from a openArray[byte] (and a way to get an immutable openArray[byte] from a string) without having to |
I propose this solution in std or fusion: func toByteSeq*(str: string): seq[byte] {.inline.} =
## Converts a string to the corresponding byte sequence.
@(str.toOpenArrayByte(0, str.high))
func toString*(bytes: openArray[byte]): string {.inline.} =
## Converts a byte sequence to the corresponding string.
let length = bytes.len
if length > 0:
result = newString(length)
copyMem(result.cstring, bytes[0].unsafeAddr, length) |
Your |
Yes, sometimes I need this. proc randomString*(size = DefaultEntropy): string {.inline.} =
## Generates a new system random strings.
result = size.randomBytesSeq.fromByteSeq And sometimes I need to debug let
serialize = [0'u8, 0, 2, 0, 8, 1, 71, 174, 20, 1, 99, 99, 0]
var str = fromByteSeq(serialize)
let
strm = newStringStream(str)
discard strm.readFrameHeaders |
IMO, the functionality is needed. When you use multiple external API, there are cases where you need one My issue with the proposed solution :
Something like this (or whatever syntax is best) : var buffer = newBuffer(bufsize)
with buffer as seq[uint16]:
# ...
with buffer as seq[byte]:
# ...
with buffer as string:
# ... |
relevant but doesn't close this issue: #15951 |
I don't think this is a "good first issue" at all because it's absolutely unclear what will be accepted and where to actually put it, even though the solution is pretty obvious. Can't we just stick template whenJSorVM(isTrue, isFalse: untyped) = # TODO: replace with a macro
when nimvm:
isTrue
else:
when (defined(js) or defined(nimdoc) or defined(nimscript)):
isTrue
else:
isFalse
func toString[T: char|byte](src: openArray[T]): string {.noinit.} =
## Returns a new string with contents copied from `src`.
result = newString(src.len)
whenJSorVM:
for i in 0..high(src):
result[i] = src[i]
do:
if src.len > 0:
copyMem(result[0].addr, src[0].unsafeAddr, src.len) anywhere and mark it as unstable API and not wait for various tangential RFC (such as nim-lang/RFCs#191)? This pattern is certainly very frequent in the wild so probably its existence is justified by now. This could be held under |
Ok, so this definitely needs to be in the Code block in my previous comment updated. |
I agree with @xflywind : Interopability between different APIs in the same codebase would be improved with this feature. |
Summary
The standard library could use a function to convert an
openarray[char]
oropenarray[byte]
to astring
.Description
Converting between byte arrays and strings is pretty common, in my experience. It's possible to cast from a
seq[char]
orseq[byte]
to astring
usingcast[string](...)
, and the compiler allows you to do the same with anopenarray
, but at runtime you get a garbage string object. (It appears that the initial bytes of the array get reinterpreted as the string's length and address.) Here's an example.This seems rather dangerous: an idiom that works in one case fails in another, but subtly enough that it might be overlooked at first. Results I've observed have been either a several-megabyte string of garbage, or an out-of-memory exception (when Nim tries to allocate a copy of a terabytes-long string.) I'm guessing that mutating the string might lead to memory corruption ... and it might be possible to craft a byte array that overwrites specific memory addresses, making this a potential security exploit.
I realize the
cast
operator is clearly documented as dangerous! The problem here isn't that using it causes undefined behavior, rather that (a) it's the only simple way to convert an array to a string, and worse, (b) it works for some types of arrays but not others.Proposal
Add some
toString(...)
procs to the system module:(
$
would be a better name, but that operator is already defined in dollars.nim, and has a different purpose.)Alternatives
The only way I've found is to create an empty string and copy the bytes:
It's a fine solution, but we shouldn't make developers use highly unsafe language features just to perform a common operation! Instead, that should be the implementation of the standard library function.
The text was updated successfully, but these errors were encountered: