-
-
Notifications
You must be signed in to change notification settings - Fork 267
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
Failing std.bitmanip unittest on Win64: peek() wrongly consumes the range #754
Comments
I've digged a little deeper. import std.stdio;
import std.range;
ubyte[T.sizeof] peek(T, R)(R range)
{
ubyte[T.sizeof] bytes;
//Make sure that range is not consumed, even if it's a class.
range = range.save;
foreach(ref e; bytes)
{
e = range.front;
range.popFront();
}
return bytes;
}
void testPeek(R)(R range)
{
auto ui32 = peek!uint(range);
auto ui16 = peek!ushort(range);
auto ui8 = peek!ubyte(range);
writeln("ui32 = ", ui32, "; ui16 = ", ui16, "; ui8 = ", ui8);
}
void test()
{
ubyte[] buffer = [1, 5, 22, 9, 44, 255, 7];
testPeek(buffer);
auto range = filter!(a => a != 0)(buffer);
testPeek(range);
}
int main()
{
test();
return 0;
} yields:
As soon as you rewrite peek() like this: ubyte[T.sizeof] peek(T, R)(R originalRange)
{
ubyte[T.sizeof] bytes;
//Make sure that range is not consumed, even if it's a class.
auto range = originalRange.save;
foreach(ref e; bytes)
{
e = range.front;
range.popFront();
}
return bytes;
} it works as expected. Note that std.algorithm.filter() returns a std.algorithm.FilterResult struct, i.e., saving shouldn't even be necessary as the range passed to peek() should be a copy already, but seems to be passed by ref! So here's the reduced problem: import std.stdio;
import std.algorithm;
void testRange(R)(R range)
{
writeln("&range in testRange(): ", cast(void*) &range);
}
void test()
{
ubyte[] buffer = [1, 5, 22, 9, 44, 255, 7];
auto range = filter!(a => a != 0)(buffer);
writeln("&range in test(): ", cast(void*) &range);
testRange(range);
}
int main()
{
test();
return 0;
} yielding something like
while the addresses should clearly differ. Looks like a severe ABI bug which may easily be the culprit of a lot of failing tests. |
import std.stdio;
struct Small { long field; }
struct Big { long field, field2; }
void testStruct(T)(T copy)
{
copy.field = 0;
}
int main()
{
Small small = { 1L };
Big big = { 1L, 2L };
testStruct(small);
testStruct(big);
writeln("small.field = ", small.field, "; big.field = ", big.field);
return 0;
} yields
|
As far as I understand this LLVM code, the byval attribute used for the argument to testStruct!Big() implies that LLVM should make a hidden copy and then pass a pointer to that dedicated copy to the callee, which it apparently doesn't. I'll try to come up with an LDC workaround, but I think it's actually an LLVM bug on Win64. |
Nice test case reduction. |
yields
ui32 = 17110537; ui16 = 11519; ui8 = 7
, i.e., the range is consumed when peek()ing (44*256+255=11519). This triggers an assertion in std.bitmanip:2640.The text was updated successfully, but these errors were encountered: