-
-
Notifications
You must be signed in to change notification settings - Fork 422
Convert _d_arraycast to template - Take 2 #2268
Conversation
|
Thanks for your pull request, @JinShil! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "master + druntime#2268" |
|
You can cut and paste the following code into http://run.dlang.io to test the implementation (be sure to add the -betterC flag): alias UnsignedStringBuf = char[20];
char[] unsignedToTempString()(ulong value, return scope char[] buf, uint radix = 10) @safe
{
if (radix < 2)
// not a valid radix, just return an empty string
return buf[$ .. $];
size_t i = buf.length;
do
{
if (value < radix)
{
ubyte x = cast(ubyte)value;
buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a');
break;
}
else
{
ubyte x = cast(ubyte)(value % radix);
value = value / radix;
buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a');
}
} while (value);
return buf[i .. $];
}
private struct TempStringNoAlloc
{
// need to handle 65 bytes for radix of 2 with negative sign.
private char[65] _buf;
private ubyte _len;
auto get() return
{
return _buf[$-_len..$];
}
alias get this;
}
auto unsignedToTempString()(ulong value, uint radix = 10) @safe
{
TempStringNoAlloc result = void;
result._len = unsignedToTempString(value, result._buf, radix).length & 0xff;
return result;
}
private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted pure
{
const(char)[][8] msgComponents =
[
"Cannot cast `"
, fromType
, "` to `"
, toType
, "`; an array of size "
, unsignedToTempString(fromSize)
, " does not align on an array of size "
, unsignedToTempString(toSize)
];
// `alloca` would be preferred here, but it doesn't work in -betterC
// See https://issues.dlang.org/show_bug.cgi?id=19159
char[1024] msg = void;
size_t index = 0;
foreach (m ; msgComponents)
foreach (c; m)
msg[index++] = c;
msg[index] = '\0';
// first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
assert(false, msg);
}
TTo[] __ArrayCast(TFrom, TTo)(TFrom[] from) @nogc pure @trusted
{
const fromSize = from.length * TFrom.sizeof;
const toLength = fromSize / TTo.sizeof;
if ((fromSize % TTo.sizeof) != 0)
{
onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
}
struct Array
{
size_t length;
void* ptr;
}
auto a = cast(Array*)&from;
a.length = toLength; // jam new length
return *cast(TTo[]*)a;
}
extern(C) void main()
{
byte[int.sizeof * 3] b = cast(byte) 0xab;
long[] l;
l = __ArrayCast!(byte, long)(b);
} |
You could do the same thing as in |
src/object.d
Outdated
| auto msg = (cast(char*)alloca(length))[0 .. length]; | ||
| // `alloca` would be preferred here, but it doesn't work in -betterC | ||
| // See https://issues.dlang.org/show_bug.cgi?id=19159 | ||
| char[1024] msg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
= void if you keep this approach.
Thanks, I wasn't aware of that technique. I'd rather go with the current approach unless someone objects. Neither approach is ideal, but it's all we have until https://issues.dlang.org/show_bug.cgi?id=18788 or https://issues.dlang.org/show_bug.cgi?id=19159 is fixed. Edit: I take that back. I noticed Edit: Nope, it doesn't work because the druntime is not linked in for -betterC, and that method requires certain druntime implementations. We just need to get dynamic stack allocation working. Back to using a static array. |
How about making |
But then I'd have to make all the other function calls inside of If you think it should be a template for reasons beyond the scope of this PR, please submit a separate PR for it. If that passes scrutiny, then I'll change the implementation in this PR. |
| auto msg = (cast(char*)alloca(length))[0 .. length]; | ||
| // `alloca` would be preferred here, but it doesn't work in -betterC | ||
| // See https://issues.dlang.org/show_bug.cgi?id=19159 | ||
| char[1024] msg = void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a classic buffer overrun opportunity. With templates, type names in D can easily get pretty long. Instead of trying to find a one size fits all number, summing the string length as before + using dynamic allocation would be more appropriate.
No, if you compile with extern (C) private pure @system @nogc nothrow
{
pragma(mangle, "fakePureErrnoImpl") ref int fakePureErrno();
pragma(mangle, "malloc") void* fakePureMalloc(size_t);
pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size);
pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size);
pragma(mangle, "free") void fakePureFree(void* ptr);
}
void* pureMalloc(bool saveRestoreErrno = true)(size_t size) @trusted pure @nogc nothrow
{
static if (saveRestoreErrno)
const errnosave = fakePureErrno();
void* ret = fakePureMalloc(size);
static if (saveRestoreErrno)
fakePureErrno() = errnosave;
else if (!ret)
{
version (D_BetterC)
assert(0, "Memory allocation failed");
else
{
import core.exception : onOutOfMemoryError;
onOutOfMemoryError();
}
}
return ret;
} |
Except for... Line 905 in e19771e
But I suppose that can be dealt with. |
|
You're right, I missed that one, because I only instantiated the template with |
|
I'm marking this "Blocked" for now. I really want to see about implementing @WalterBright's suggestion at https://issues.dlang.org/show_bug.cgi?id=18788 to have |
allocadoesn't work in -betterC. See https://issues.dlang.org/show_bug.cgi?id=19159.mallocwon't work either because it isn'tpure. So, I just resorted to a hard-coded static array.