A bug in my code

Denis Koroskin 2korden at gmail.com
Sat Sep 6 12:09:56 PDT 2008


On Sat, 06 Sep 2008 05:12:56 +0400, bearophile <bearophileHUGS at lycos.com>  
wrote:

> This code isn't short, but can someone help me spot the bug/problem (D1,  
> DMD)?
> I have tried to write clean & short code, to help spotting problems.
>
> It produces an (no error line given):
> Error: overlapping array copy
>
> It's just a stack data structure (here for simplicity just for items of  
> type int), made with a single linked list of blocks that become  
> geometrically bigger.
>
>
> import std.gc: malloc, hasNoPointers;
>
> int min(int a, int b) {
>     return a <= b ? a : b;
> }
>
>
> class IntStack {
>     struct Block {
>         int len;
>         Block* next;
>         int* data;
>     }
>
>     Block* list_head, list_tail;
>     int total_len;
>     int used_last_block; // how many items are used in the last (tail)  
> block
>
>
>     this() {
>         this.list_head = block_alloc(4);
>         this.list_tail = list_head;
>     }
>
>
>     ubyte* mem_alloc(int nbytes) {
>         auto p  = cast(ubyte*)malloc(nbytes);
>         if (p is null)
>             throw new Error("not enough mem");
>         hasNoPointers(p);
>         return p;
>     }
>
>
>     Block* block_alloc(int nints) {
>         auto new_block = cast(Block*)mem_alloc(Block.sizeof);
>         new_block.data = cast(int*)mem_alloc(nints * int.sizeof);
>         new_block.len = nints;
>         new_block.next = null;
>         return new_block;
>     }
>
>
>     final void opCatAssign(int x) {
>         if (this.used_last_block == this.list_tail.len) {
>             // then last block is full and we must create a new one
>             this.used_last_block = 0;
>             auto new_block = block_alloc(this.list_tail.len * 2);
>
>             // append to the linked list
>             this.list_tail.next = new_block;
>             this.list_tail = new_block;
>         }
>
>         this.list_tail.data[this.used_last_block] = x;
>         this.used_last_block++;
>         this.total_len++;
>     }
>
>
>     int[] toarray() {
>         if (!this.total_len)
>             return null;
>
>         int* result_ptr = cast(int*)mem_alloc(this.total_len *  
> int.sizeof);
>         int[] result = result_ptr[0 .. this.total_len];
>
>         Block* aux_ptr = this.list_head;
>         int pos;
>
>         // Here: Error: overlapping array copy
>         while (aux_ptr != null) {
>             // in the last block copy only up to the total_len
>             int ncopy = min(aux_ptr.len, this.total_len - pos);
>            result[pos .. pos + ncopy] = aux_ptr.data[0 .. ncopy];
>             pos += ncopy;
>             aux_ptr = aux_ptr.next;
>         }
>
>         return result;
>     }
> }
>
>
> void main() {
>     auto st = new IntStack();
>
>     for (int i; i < 70_000; i++)
>         st ~= i;
>
>     auto aux = st.toarray;
>     aux = st.toarray;
> }
>
>
>
> ---------------------
>
> Note: in that code I haven't used variable-length structs, like the  
> following idiom sometimes used in C, because it gives array bounds  
> errors:
>
>
> struct Block {
>     int len;
>     Block* next;
>     int[1] data;
> }
> ...
> auto new_block = cast(Block*)mem_alloc(Block.sizeof + (nints - 1) *  
> int.sizeof);
>
>
> I presume that can't be done in D (I don't want to write code that works  
> only in release mode).
>
> Bye and thank you,
> bearophile

Just started digging your case. This behaviour is 100% repeatable with  
DMD1.028 but never takes place with DMD1.029+ (Windows).


More information about the Digitalmars-d-learn mailing list