digitalmars.D - BufferedFile bug?
- Regan Heath (68/68) Mar 06 2008 Hey,
- Oskar Linde (17/26) Mar 06 2008 Congratulations, you found another stupid integer promotion rule bug.
- Janice Caron (24/28) Mar 06 2008 (I changed the variable names because lowercase L looks like one to me).
- bearophile (5/10) Mar 06 2008 Delphi has runtime cheeks for integer overflow too, they help.
- Frits van Bommel (9/10) Mar 06 2008 I'm sorry. I don't usually mind misspellings so much, but this one is
- bearophile (6/11) Mar 06 2008 This language is my third one, and it shows.
- Oskar Linde (19/51) Mar 06 2008 It is hard to classify something as a bug when it behaves exactly as
- Janice Caron (3/5) Mar 06 2008 Gosh - I've clearly missed out on that rather interesting line of
- Lionello Lunesu (7/37) Mar 06 2008 Andrei Alexandrescu posted a .pdf a while back with a graph containing a...
- Lionello Lunesu (2/2) Mar 06 2008 Found it:
- Janice Caron (17/19) Mar 07 2008 I tried downloading that (unsuccessfully). However, it seems to me
- Saaa (2/2) Mar 06 2008 Is there a place where it lists the specific specs which, as this promot...
- Regan Heath (4/37) Mar 11 2008 When the file ended up that close to 4gb each time I did suspect an
Hey, [DMD 2.010, windows] So.. was doing a bit of simple D coding and got some really odd behaviour, namely this code creates a 4gb (4,294,975,895 bytes) file on my disk! My question is, is this a bug or am I doing something stupid? The idea is to open a file and overwrite random blocks with '0' (the ascii number, not the decimal value - though I get the same behaviour with either). When executed this code seems to hang after outputting "Close.." and at that point the file is growing, and growing... ctrl+c does nothing immediately but seems to work after the file reaches 4gb, at a guess when close actually returns. Opening the file in textpad only shows 8232 characters, all 'a' - so none of the modifications have been applied and it seems an eof character has been inserted at that point in the 4gb file. Adding a return after the file creation before the modification shows a file which is as expected 50000 characters long, all 'a'. So that at least is working as expected. import std.stdio; import std.stream; import std.file; import std.random; int main() { // Create small file auto f = new BufferedFile("test", FileMode.OutNew); int size = 50000; for(int i = 0; i < size; i++) f.write('a'); f.close; // Open and modify f = new BufferedFile("test", FileMode.In | FileMode.Out); ulong total = getSize("test"); long block = total/1000; long offset; long bytes; Random gen; writefln("Total: %d,%d", total, block); for(int i = 0; i < 2; i++) { offset = uniform!(long)(gen, 0L, block); bytes = uniform!(long)(gen, 0L, block); writefln("Seek : %d,%d,%d", f.position, offset, bytes); f.seekCur(offset); writefln("Mod : %d,%d", f.position, bytes); for(long j = 0; j < bytes; j++) f.write('0'); writefln("Done : %d", f.position); } writefln("Close: %d", f.position); f.close; writefln("Done"); return 0; }
Mar 06 2008
Regan Heath wrote:Hey, [DMD 2.010, windows] So.. was doing a bit of simple D coding and got some really odd behaviour, namely this code creates a 4gb (4,294,975,895 bytes) file on my disk! My question is, is this a bug or am I doing something stupid?Congratulations, you found another stupid integer promotion rule bug. Those have been a personal gripe for me. Hopefully we can one day fix this horrible design mistake from C. The problem is that: uint l = 1; long c = -l; yields c == 4294967295 wohoo... (Did I mention that I hate those?) The error lies in BufferedStream.flush() BufferedStream has a uint bufferSourcePos and does: if (bufferSourcePos != 0 && seekable) { // move actual file pointer to front of buffer streamPos = s.seek(-bufferSourcePos, SeekPos.Current); and since seeks first argument is a long, it gets a value close to 4GB. -- Oskar
Mar 06 2008
On 06/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:The problem is that: uint x = 1; long y = -x; yields y == 4294967295(I changed the variable names because lowercase L looks like one to me). Huh? Why doesn't y equal minus one? I wouldn't call that a bug in BufferedStream.flush(), I'd call it a bug in D's arithmetic generally. The way I see it, there are two possible fixes: (1) Disallow unary minus completely for all unsigned types. Thus uint x = 1; long y = -x; /*ERROR*/ forcing the user to explicitly write long y = -cast(int)x; or long y = -cast(long)x; either of which should be OK, or (2), when unary minus is applied to an unsigned type, promote ubyte to short, ushort to int, uint to long, ulong to cent (...best make that one illegal for now). That would mean uint x = 1; long y = -x; /* OK */ but uint x = 1; int y = -x; /* Error */ Either would work, but the status quo /can't/ be right!!!???
Mar 06 2008
Janice Caron:I wouldn't call that a bug in BufferedStream.flush(), I'd call it a bug in D's arithmetic generally.Another faster solution is to avoid unsigned integrals whenever you can, so you can avoid some bugs.(2), when unary minus is applied to an unsigned type, promote ubyte to short, ushort to int, uint to long, ulong to cent (...best make that one illegal for now). That would meanDelphi has runtime cheeks for integer overflow too, they help. Bye, bearophile
Mar 06 2008
bearophile wrote:Delphi has runtime cheeks for integer overflow too, they help.I'm sorry. I don't usually mind misspellings so much, but this one is really getting on my nerves. Maybe it's the fact you repeat it so often, combined with the fact the misspelling has an entirely different meaning; I don't know. It's "checks". Not "cheeks". Compare: http://dictionary.reference.com/search?q=check http://dictionary.reference.com/search?q=cheek
Mar 06 2008
Frits van Bommel:I'm sorry. I don't usually mind misspellings so much, but this one is really getting on my nerves. Maybe it's the fact you repeat it so often, combined with the fact the misspelling has an entirely different meaning; I don't know. It's "checks". Not "cheeks".This language is my third one, and it shows. Don't be sorry, I'll try to remember it, checks! If you find other problems in my language please feel free to tell me. Thank you very much, bearophile
Mar 06 2008
Janice Caron wrote:On 06/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:It is hard to classify something as a bug when it behaves exactly as specified. See "Usual Arithmetic Conversion" under: http://www.digitalmars.com/d/1.0/type.html This is exactly how it works in C too.The problem is that: uint x = 1; long y = -x; yields y == 4294967295(I changed the variable names because lowercase L looks like one to me). Huh? Why doesn't y equal minus one? I wouldn't call that a bug in BufferedStream.flush(), I'd call it a bug in D's arithmetic generally.The way I see it, there are two possible fixes: (1) Disallow unary minus completely for all unsigned types. ThusUnary minus is not the only affected operator. All integer arithmetic is affected.(2), when unary minus is applied to an unsigned type, promote ubyte to short, ushort to int, uint to long, ulong to cent (...best make that one illegal for now). That would mean uint x = 1; long y = -x; /* OK */ but uint x = 1; int y = -x; /* Error */ Either would work, but the status quo /can't/ be right!!!???There has been some previous discussions along those lines. For example: http://www.digitalmars.com/d/archives/digitalmars/D/unsigned_policy_47929.html#N47954 Today, all arithmetic operations are promoted to int/uint, and by the magic of the 2's-complement representation, things actually work out most of the time. for example: int a = (rand() % 3) - 1; works fine, while double b = (rand() % 3) - 1; doesn't. -- Oskar
Mar 06 2008
On 06/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:There has been some previous discussions along those lines. For example: http://www.digitalmars.com/d/archives/digitalmars/D/unsigned_policy_47929.html#N47954Gosh - I've clearly missed out on that rather interesting line of conversation. Thanks for the link.
Mar 06 2008
"Janice Caron" <caron800 googlemail.com> wrote in message news:mailman.118.1204810684.2351.digitalmars-d puremagic.com...On 06/03/2008, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:Andrei Alexandrescu posted a .pdf a while back with a graph containing all types and directed edges for all allowed implicit promotions.. I think he has it on his site, but I can't seem to access it (erdani.org) from China. Has he been politcally active lately?? : ) L.The problem is that: uint x = 1; long y = -x; yields y == 4294967295(I changed the variable names because lowercase L looks like one to me). Huh? Why doesn't y equal minus one? I wouldn't call that a bug in BufferedStream.flush(), I'd call it a bug in D's arithmetic generally. The way I see it, there are two possible fixes: (1) Disallow unary minus completely for all unsigned types. Thus uint x = 1; long y = -x; /*ERROR*/ forcing the user to explicitly write long y = -cast(int)x; or long y = -cast(long)x; either of which should be OK, or (2), when unary minus is applied to an unsigned type, promote ubyte to short, ushort to int, uint to long, ulong to cent (...best make that one illegal for now). That would mean uint x = 1; long y = -x; /* OK */ but uint x = 1; int y = -x; /* Error */ Either would work, but the status quo /can't/ be right!!!???
Mar 06 2008
Found it: http://erdani.org/d-implicit-conversions.pdf
Mar 06 2008
On 07/03/2008, Lionello Lunesu <lionello lunesu.remove.com> wrote:Found it: http://erdani.org/d-implicit-conversions.pdfI tried downloading that (unsuccessfully). However, it seems to me that we don't need a diagram. The rule can be easily expressed purely in logic. It is safe to implicitly convert from type T to type U, if and only if both of the following two rules apply: (1) There exists no value x of type T for which cast(T) cast(U) x != x (2) There exists no value x of type T, and no type V, for which cast(V) x != cast(V) cast(U) x Finding a single counterexample to either of those rules is sufficient to prove a conversion unsafe. For example, one cannot safely implicitly cast an int to a short, because rule (1) is violated (e.g. with counterexample x == 0x10000). Likewise, one cannot safely implicitly cast a uint to an int, because rule (2) is violated (e.g. with counterexample x == 0xFFFFFFFF and V == long) Well, that blows C integer promotion rules out of the window! :-)
Mar 07 2008
Is there a place where it lists the specific specs which, as this promotion, are that error prone?
Mar 06 2008
Oskar Linde wrote:Regan Heath wrote:When the file ended up that close to 4gb each time I did suspect an signed/unsigned bug. Did anyone make a bug report or should I do so now? ReganHey, [DMD 2.010, windows] So.. was doing a bit of simple D coding and got some really odd behaviour, namely this code creates a 4gb (4,294,975,895 bytes) file on my disk! My question is, is this a bug or am I doing something stupid?Congratulations, you found another stupid integer promotion rule bug. Those have been a personal gripe for me. Hopefully we can one day fix this horrible design mistake from C. The problem is that: uint l = 1; long c = -l; yields c == 4294967295 wohoo... (Did I mention that I hate those?) The error lies in BufferedStream.flush() BufferedStream has a uint bufferSourcePos and does: if (bufferSourcePos != 0 && seekable) { // move actual file pointer to front of buffer streamPos = s.seek(-bufferSourcePos, SeekPos.Current); and since seeks first argument is a long, it gets a value close to 4GB.
Mar 11 2008