[gnu.g++.bug] Compiler catches signal 6 ...

andersnb@LAB.ULTRA.NYU.EDU (Brian Anderson) (09/28/89)

Date: Wed, 27 Sep 89 16:14:38 EDT
From: Mail Delivery Subsystem <MAILER-DAEMON@shasha.cs.nyu.edu>
Subject: Returned mail: User unknown
To: andersnb@shasha.cs.nyu.edu

   ----- Transcript of session follows -----
550 bug-g++... User unknown

   ----- Unsent message follows -----
Received:  by shasha.cs.nyu.edu (3.2/25-eef)
	id AA04631; Wed, 27 Sep 89 16:14:38 EDT
Date: Wed, 27 Sep 89 16:14:38 EDT
From: Brian G. Anderson <andersnb>
Full-Name: Brian G. Anderson
Message-Id: <8909272014.AA04631@shasha.cs.nyu.edu>
To: bug-g++
Subject: g++ reports that cc1plus caught signal 6...

The two files included after this mail text (files.cc files.h) cause
g++ to report that cc1plus caught signal 6 when run with the following
command line:

g++ -c files.cc

The code has many coding errors (I was attempting to debug the code at
the time), but no other errors are reported except the signal error.
I run this on a SUN 3/50 with SUN OS 3.5.  My g++ compiler version is
"1.35.1-".  I poked around a little: I preprocessed the file seperatly
and ran cc1plus on the preprocessed file.  The program reported the
errors in the code.  After running cc1plus under gdb I could catch no
signal 6; cc1plus ran fine.  Could you see what's going on..

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Brian G. Anderson                                       |
NYU Ultracomputer Research Project                     |||
715 Broadway  Rm. 1006                                |||||
New York, NY  10003                                   |||||
(212) 998-3346                                     --- //\ ---
arpa:	andersnb@cmcl2                             ----/ \----
uucp:	{ihnp4,seismo}!cmcl2!andersnb              ----   ----


*************files.h**************
/* Files.h
   contains the declarations for the memory buffer class and the tupl
file layout routines.
*/

#include <builtin.h>
#include "errors.h"

/* The in memory page structures.  Memory pages are variable length,
but must have enough room for
sizeof(weight_val)+sizeof(int)+sizeof(owner_val).  Any remaining space
is referenced through the data pointer.  A disk page must fit into the
data space of a memory page.  Each page has an owner and a weight when
it is in use.  The greater the weight the greater the difficulty in
"lifting" the pages contents out of memory to make room.  */

typedef int weight_val;
typedef int owner_val;
typedef int page_idx;

class mem_page {
 private:
  enum {dirty=0, locked = 1, pinned = 2};
  weight_val heavy;
  long flags;
  owner_val own_id;
  
 public:
  char data[0];

  inline void in_use(const owner_val own, const weight_val wght)
    {if(own != 0) fatal("mem_page::in_use","page is not free");
     own_id = own; heavy = wght;}
  inline void clearflags() {flags=0;}
  inline void soiled() {setbit(flags,dirty);}
  inline void clean() {clearbit(flags,dirty);}
  inline int issoiled() {return testbit(flags, dirty);}
  inline void lock() {setbit(flags,locked);}
  inline void unlock() {clearbit(flags,locked);}
  inline int islocked() {return testbit(flags,locked);}
  inline void free() {own_id=0;}
  inline owner_val owner() {return own_id;}
  inline weight_val weight() {return heavy;}
};

/* This is the memory pages class.  The programmer specifies the
number of pages and the size at compiler time.  This class is meant to
be inherited for use by objects that will use the memory pages buffer
pool to bring things in and out of memory from disk.  On shared
everything machine architectures, objects derived from mem_pages are
guaranteed to be in shared memory.  When this is working fully,
concurrent access will be supported.*/

class mem_pages: errors {
 private:
  int p_size;
  int n_pages;
  char *pages;

 public:
  inline mem_pages(int size, int number) {
    pages = new char[size*number];
    p_size= size;
    n_pages = number;
  }

  inline ~mem_pages() { delete pages;}

  inline mem_page& operator[](page_idx idx) {
    // check if the index is in the range of the object;
    if(idx > n_pages) error("mem_pages::[]","invalid index");
      
    return *((mem_page*)(&pages[idx*p_size]));
  }
  inline int page(void *ptr) {
    if(ptr < (void*) pages || ptr - (void*)pages > n_pages*p_size)
      fatal("mem_pages::lock","pointer not in range of memory pages");
    return ((long)pages - (long)ptr)/p_size;
  }
  inline void lock(int idx) {(*this)[idx].lock();}
  inline void lock(void *ptr) {(*this)[page(ptr)].lock();}
  inline void unlock(int idx) {(*this)[idx].unlock();}
  inline void unlock(void *ptr) {(*this)[page(ptr)].unlock();}
  inline int islocked(int idx) {(*this)[idx].islocked();}
  inline int islocked(void *ptr) {return (*this)[page(ptr)].islocked();}

  inline int number_pages() {return n_pages;}
  inline int page_size() {return p_size;}

  page_idx find_free(int, int);

//  int save_page()=0;
};


**********
******files.cc**********
#include "files.h"

/* Memory Pages Methods */
int mem_pages::find_free(int own, int wgt) {
  for(int i=0; i<n_pages; i++)
    if((*this)[i].owner == 0) {
      (*this)[i].in_use(own, wgt);
      (*this)[i].clearflags();
      return i;
    }

  fatal("mem_pages::find_free","insufficient memory pages");
}

/* Hashing on memory pages */
/* This is the hash pointer class.  It will be inherited by any class requiring
hash tables of some object.  The index operation "[]" only understands ints.
It is up to the derived class to hash the actual indexed value to an int.
Six virtual function must be defined by the derived class:

a) "first(contents_ptr)" - go to the first element in the bucket.  The
function returns 0 if no first element exists.  On return contents_ptr
references the first element.

b) "next(contents_ptr)" - find the next element after the one pointed
to by bucket_ptr.  On return from function bucket_c_ptr points to
next.  The function returns 0 if no next element exists in this
bucket.

c) "get_free(contents_ptr)" - find space for a new element in the
bucket.  If no space is to be found the function returs 0.  On return
contents_ptr references the newly allocated space.

d) "delete(contents_ptr)" - free element pointed to by contents_ptr.

e) "index(contents_ptr)" - report the index of the element pointed to
by contents_ptr.

f) "move(contents_ptr, contents_ptr)" - move the first element to the
second element.  The pointers are not necessarily on the same page.

g) "n_free(contents_ptr)" - amount of free elements in this bucket;

These functions are used by hash table code to manipulate the table
bucket contents.  Logically these functions should appear in the
bucket_ptr, however since we want no virtual functions in the mem_pages
they must appear in the pointer.
*/

class contents_ptr;
class hash_ptr {
protected:
  mem_pages *mem;
  page_idx idx;

  virtual void del(const contents_ptr&)=0;
  virtual int get_free(page_idx, contents_ptr&)=0;
  virtual int n_free(contents_ptr&)=0;
  virtual int index(const contents_ptr&)=0;
  virtual int next(contents_ptr&)=0;
  virtual int first(page_idx, contents_ptr&)=0;
  virtual int move(contents_ptr&, contents_ptr&)=0;

  inline hash_ptr(mem_pages *m, page_idx i) {mem = m; idx = i;}
  contents_ptr operator[](int);
  struct hash_bucket* find_index(struct hash_header&,int& idx);
};

class contents_ptr {
protected:
  page_idx c_idx;
  int offset;
  
  inline contents_ptr(hash_ptr& h_p) {c_idx=0; offset=0;}
};

/* Hash table structures: we need these to manipulate the contents of
the mem_pages in a defined way.  The idea is cast the pointer to the
mem_page data contents to a pointer to one of the hash structures.
Then do all manipulations through the structure pointer.  !Remember!
No virtual functions!  */

struct hash_header {
  int slots_used;
  page_idx link;
  page_idx data[0];
  inline int hash(const int& index){
    int t_sig =  lg(slots_used);
    if(1<<t_sig != slots_used) t_sig++;

    int t_idx = (index & ~(~0 << t_sig));

    if(t_idx > slots_used -1 ) t_idx & ~(1 << (t_sig -1));
  }
};

struct hash_bucket {
  page_idx link;
  int n_elem;
  char data[0];
};

/* Hash pointer methods */
contents_ptr hash_ptr::operator[](int index){
  const int max_on_page =  (mem->page_size - sizeof(struct hash_header))/
    sizeof(page_idx);
  
  // lock the head of the hash table in memory
  // int keep = mem->islocked(idx);
  // mem->lock(idx);
  struct hash_header *h_head = (struct hash_header *) (*mem)[idx].data;
  
  // does the header have any elements in it?
  if(!h_head->slots_used) {
    // the table is completely empty
    h_head->slots_used = 1;
    h_head->data[0] = mem->find_free(1,1);
    if(h_head->data[0] = 0)
      fatal("hash_ptr::[]","find_free unable to find free page");
    
    struct hash_bucket *b_ptr = (struct hash_bucket*)(*mem)[idx].data;
    h_bucket->n_elem = 0;
    h_bucket->link = 0;
    // new page so it's dirty
    (*mem)[idx].soiled();
    return;
  }
  
  // find the appropriate bucket chain.  first find the number of significant
  // digits and mask all but those from index.  If index is still greater than
  // the number of entries in the table the most significant bit of the index
  // of the index will be removed to yield a valid index.  This index finds
  // the bucket pointer to the first bucket in the chain of buckets for 
  // this hash value.
  int e_idx = h_head->hash(index);
  struct hash_table* e_table = h_head;
  int o_e_idx = e_idx;
  
  // move to the appropriate header page
  struct hash_bucket* e_ptr = find_index(e_table, o_e_idx);
  struct hash_bucket* b_ptr = e_ptr;
  
  // we have a bucket chain, follow it looking for desired index
  int ff= 0, pages_seen = 0;
  
  while(1){
    content_ptr c_ptr(*this);
    
    // Check if contents of bucket is empty
    if(!first(mem->page(b_ptr), c_ptr))
      fatal("hash_ptr::[]","found empty bucket in chain");
    
    // start searching for element in the bucket
    do {
      if(index(c_ptr) == index)
	return c_ptr;
    } while(next(c_ptr));
    
    // didn't find any element with the desired index
    // is there any space that could be used later?
    ff ^= n_free(c_ptr);
    pages_seen++;
    
    // follow link to next bucket
    if(b_ptr->link)
      b_ptr = (struct hash_bucket *)(*mem)[b_ptr->link].data;
    else break;
  }
  
  // The index wasn't found. Check if there are too many buckets on this chain
  // or the element we will add is going to overflow
  
  if(pages_seen > bucket_max || (pages_seen + 1 == bucket_max && !ff)){
    // caclulate the bucket indicies
    int s_l_idx = h_head->hash(h_head->slots_used);
    int s_h_idx = ++(h_head->slots_used);
    
    // are we splitting the bucket we will add to?
    int split_add = (e_idx == s_h_idx);
    
    // move to low bucket
    struct hash_table* s_l_table = h_head;
    struct hash_bucket* s_l_ptr = find_index(s_l_table, s_l_idx);
    if(s_l_idx == -1)
      fatal("hash_ptr::[]","unable to find low element in hash table");
    
    // move to high bucket, but we might have to create it first
    struct hash_table* s_h_table = s_l_table;
    struct hash_bucket* s_h_ptr = find_index(s_h_table, s_h_idx);
    if(s_h_idx == -1){
      s_h_table->link = mem->find_free(1,1);
      s_h_table = (struct hash_bucket*)(*mem)[s_h_table->link].data;
      s_h_table->link = 0;
      s_h_idx = 0;
    }
    
    // set up for splitting the buckets
    struct hash_bucket* source_ptr = s_l_ptr;
    s_l_table->data[s_l_idx] = mem->find_free(1,1);
    s_l_ptr = (struct hash_bucket*)(*mem)[s_l_table->data[s_l_idx]].data;
    s_l_ptr->link = 0;
    s_l_ptr->n_elements = 0;
    s_h_table->data[s_h_idx] = mem->find_free(1,1);
    s_h_ptr = (struct hash_bucket*)(*mem)[s_h_table->data[s_h_idx]].data;
    s_l_ptr->link = 0;
    s_l_ptr->n_elements = 0;
    
    // if added element will move then point to high bucket if that is new
    // hash bucket.
    if(split_add && h_head->hash(index) == s_h_idx){
      e_table = s_h_table;
      e_ptr = s_h_ptr;
      o_e_idx = s_h_idx;
    }
    
    // move down source chain moving to appropriate high/low bucket according
    // to the new hashed index.
    contents_ptr s_c_ptr(*this);
    if(!first(mem->page(source_ptr), s_c_ptr))
      fatal("hash_ptr::[]","found empty bucket in chain");
    contents_ptr h_c_ptr(*this);
    contents_ptr l_c_ptr(*this);
    while(){
      if(h_head->hash(s_c_ptr.index) == s_h_idx){
	d_c_ptr = &h_c_ptr;
	d_ptr = &s_h_ptr;
      } else if(h_head->hash(s_c_ptr.index) == s_l_idx){
	d_c_ptr = &l_c_ptr;
	d_ptr = &s_l_ptr;
      } else
	fatal("hash_ptr::[]","index doesn't agree with any split index");

      if(!h_head->get_free(mem->page(*d_ptr),*d_c_ptr)){
	// no more space in this bucket so make new one
	(*d_ptr)->link = mem->find_free(1, 1);
	*d_ptr = (struct hash_bucket*)(*mem)[(*d_ptr)->link].data;
	(*d_ptr)->link = 0;
	(*d_ptr)->n_elements = 0;
      }

      // move the item
      move(s_c_ptr,*d_c_ptr);

      // move to next item
      if(!s_c_ptr.next()){
	// no more items in this unit so move to next in bucket
	if(!source_ptr->link){
	  (*mem)[mem->page(source_ptr)].free();
	  break;
	}
	if(!first(source_ptr->link, s_c_ptr))
	  fatal("hash_ptr::[]","empty bucket on chain");
	
	// move to next bucket and free the old one
	struct hash_bucket* old = source_ptr;
	source_ptr = (struct hash_bucket*)(*mem)[source_ptr->link].data;
	(*mem)[mem->page(old)].free();
      }
}}

// everything is kosher now so get a free element from the proper bucket
while(1){
  content_ptr c_ptr(*this);
  
  // didn't find any element with the desired index
  // is there any space that could be used later?
  if(get_free(mem->page(e_ptr),c_ptr))
    return c_ptr;
  
  // didn't find any thing, follow link to next bucket
  if(e_ptr->link)
    e_ptr = (struct hash_bucket *)(*mem)[e_ptr->link].data;
  else {
    // ran out of buckets so make a new one
    e_ptr->link = mem->find_free(1 , 1);
    e_ptr = (struct hash_bucket *)(*mem)[e_ptr->link].data;
    e_ptr->link = 0;
  }
}
}

struct hash_bucket *hash_ptr::find_index(struct hash_header& h_table,
					 int& idx){
  const int max_on_page =  (mem->page_size - sizeof(struct hash_header))/
    sizeof(page_idx);

  int skip = idx / max_on_page;
  int offset = idx % max_on_page;

  // skip to the appropriate header page
  for(;skip;skip--){
    // check if there is a link to follow
    if(!h_table->link){
      idx = -1;
      return 0;
    }

    h_table = (struct hash_header *) (*mem)[h_table->link].data;
  }

  idx = offset;

  // return the pointer to the bucket
  return (struct hash_bucket *)(*mem)[h_table->data[offset]].data;
}