I checked out Parrot from CVS on 2002Aug30 to an IRIX64 system. shell01:/usr/tmp/swmcd/parrot>uname -a IRIX64 shell01 6.5 07201611 IP27
make compiled OK. make test failed all the t/pmc/perlhash.t tests. Running parrot t/pmc/perlhash_1.pbc produced a bus error. I chased the error down to parrot/hash.c: new_bucket(), at the line marked below. static BucketIndex new_bucket(Interp *interpreter, HASH *hash, STRING *key, HASH_ENTRY *value) { BucketIndex bucket_index; if (key == NULL) { internal_exception(INTERNAL_PANIC, "NULL key\n"); return NULLBucketIndex; } if (value == NULL) { internal_exception(INTERNAL_PANIC, "NULL value\n"); return NULLBucketIndex; } bucket_index = hash->free_list; if (bucket_index != NULLBucketIndex) { HASHBUCKET *bucket = getBucket(hash, bucket_index); hash->free_list = bucket->next; bucket->key = key; ====>>>> bucket->value = *value; <<<<==== BUS ERROR HERE return bucket_index; } /* Free list is empty. Need to expand the hashtable. */ expand_hash(interpreter, hash); return new_bucket(interpreter, hash, key, value); } bucket->value is a HASH_ENTRY, which is declared in parrot/include/parrot/hash.h as typedef struct _hash_entry { HASH_ENTRY_TYPE type; UnionVal val; } HASH_ENTRY; A little hacking showed that the bus error was occurring on the assignment of val. val is a UnionVal, declared in parrot/include/parrot/interpreter.h as typedef union UnionVal { INTVAL int_val; FLOATVAL num_val; DPOINTER* struct_val; STRING* string_val; PMC* pmc_val; } UnionVal; Some printf's further showed that (*value).val was 8-byte aligned, while bucket->value.val was 4 byte aligned. sizeof(FLOATVAL) is 8 on IRIX64, so this starts to look like a memory alignment problem. The next interesting question is how bucket->value.val got be 4-byte aligned. Here is a (very) schematic account of where bucket->value.val comes from new_bucket() get_bucket() hash->bucket_pool->bufstart new_hash() expand_hash() Parrot_reallocate() mem_allocate() mem_allocate() is declared in resources.c as static void * mem_allocate(struct Parrot_Interp *interpreter, size_t *req_size, struct Memory_Pool *pool, size_t align_1) mem_allocate() allocates memory from a Memory_Pool. A Memory_Pool manages a list of Memory_Block's. A Memory_Block manages a single block of memory. It is declared as struct Memory_Block { size_t free; size_t size; struct Memory_Block *prev; struct Memory_Block *next; char *start; char *top; }; start points to the entire block of memory, and top points to the next byte to be allocated from the block. Initially, top is equal to start. Each call to mem_allocate() advances top by the size of the block to be allocated and then returns the previous value of top. The align_1 parameter to mem_allocate() does not--as you might think--control the alignment of the allocated block. Rather, it controls the *size* of the allocated block, rounding it up to the next multiple of the power of 2 indicated by align_1. This means that the alignment of a block returned by mem_allocate() is dependent on the *previous* calls to mem_allocate(). printf's show that start is 8-byte aligned on my system. As it happens, something upstream of new_bucket() calls mem_allocate() to allocate 18 bytes with an alignment of 4. mem_allocate() dutifully rounds 18 up to 20 (the next multiple of 4) and allocates 20 bytes from the block. (Plus some headers and padding, but the sizes of these are both multiples of 8, so they don't affect what happens next.) This puts top at a 4-byte aligned address. Later, when new_bucket() obtains storage from mem_alloc(), it gets the 4-byte aligned block, and the bus error follows. I tested this theory by hacking mem_allocate() to enforce a minimum round-up to an 8-type boundary. /* Round up to requested alignment */ if (align_1<7) align_1 = 7; /* <<<==== HACK */ size = (size + align_1) & ~align_1; This keeps top 8-byte aligned. The bus error went away, and t/pmc/perlhash_1.pbc produced the correct output. I don't know how this thing is supposed to work, so I don't know how to fix it. Logically, there are a few possibilities. 1. Fix gcc on IRIX64 to permit assignment of unions with arbitrary alignment. 2. Add a parameter to mem_alloc() (or use align_1) to control the alignment of the allocated block. 3. Require all callers of mem_alloc() to pass an align_1 parameter big enough to meet the alignment requirements of the platform. (Seems like the Wrong Thing.) - SWM