簡體   English   中英

自己的 Malloc 實現凍結在 brk

[英]Own Malloc implementation freeze at brk

為了練習,我目前正在嘗試在 c 中編寫自己的 malloc function。 所以我的問題是,在從堆中進行一些分配后,我的程序將凍結。 我找到了導致凍結的代碼段,當我調用 brk sys 調用時它會凍結。 我已經嘗試在那里解鎖我的互斥鎖,但這沒有用。 為了測試它,我編寫了一個永久循環並在一個數組中分配 memory 並隨機釋放它。

static list *head = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

typedef struct list
{         
  size_t size_;                
  int free_;                  
  struct list *next_;      
  struct list *previouse_;
} block;

void blockAdd(block *href, size_t size)
{
  href->free_ = FALSE;
  href->next_ = NULL;
  href->previouse_ = NULL;

  if (!head || head > href)
  {
    if (head)
    {
      head->previouse_ = href;
    }
    href->size_ = size + sizeof(block);
    href->next_ = head;
    head = href;
  }
  else
  {
    href->next_ = NULL;
    block *current = head;

    while (current->next_ && current->next_ < href)
    {
      current = current->next_;
    }
    href->size_ = size + sizeof(block);
    href->next_ = current->next_;
    href->previouse_ = current;
    current->next_ = href;
  }
}

void *findExactSizeMatch(size_t size)
{
  block *href = head;
  size_t t = size + sizeof(block);

  while (href)
  {
    if (href->size_ == (size + sizeof(block)) && href->free_)
    {
      href->free_ = FALSE;
      return href;
    }
    href = href->next_;
  }
  return NULL;
}

void *findLagerBlock(size_t size)
{
  block *href = head;

  while (href)
  {
    if (href->free_ && href->size_ > size)
    {
      return split(href, size);
    }
    href = href->next_;
  }

  return NULL;
}

void *allocateMemory(size_t size)
{
  block *new_block = sbrk(BLOCK_SIZE(size));

  if (new_block == SBRK_FAILED)
  {
    exit(1);
  }
  blockAdd(new_block, size);

  return new_block;
}

bool checkAllFree()
{
  block *href = head;

  while (href)
  {
    if (!href->free_)
    {
      return FALSE;
    }
    href = href->next_;
  }
  return TRUE;
}

void freeList(block *ptr)
{
  if (checkAllFree())
  {
    if (brk(ptr) == BRK_FAILED)
    {
     exit(1);
    }
    head = NULL;
  }
}

void merge()
{
  block *href = head;

  while (href && href->next_)
  {
    if (href->free_ && href->next_->free_)
    {
      href->size_ = href->next_->size_;
      href->next_ = href->next_->next_;
    }
    href = href->next_;
  }
}

//--------------------------Here it makes some strange things
shrinkHeap()
{
  block *href = head;

  while (href && href->next_)
  {
    href = href->next_;
  }

  if (href && href->free_)
  {
    if (brk(href) == BRK_FAILED)
    {
      exit(1);
    }
    href->previouse_->next_ = href->next_;
  }
}

void *malloc(size_t size)
{
  if (!size)
  {
    return NULL;
  }
  pthread_mutex_lock(&mutex);

  block *new_list = NULL;

  new_list = findExactSizeMatch(size);
  if (new_list)
  {
    pthread_mutex_unlock(&mutex);
    return new_list + sizeof(block);
  }

  new_list = allocateMemory(size);
  pthread_mutex_unlock(&mutex);

  return new_list + sizeof(block);
}

void free(void *ptr)
{
  if (!ptr || !head)
  {
    return;
  }
  pthread_mutex_lock(&mutex);

  block *pref = ptr - sizeof(block);

  pref->free_ = TRUE;

  freeList(pref);
  shrinkHeap();
  merge();

  pthread_mutex_unlock(&mutex);
}

我不知道為什么,但是 brk 凍結了我的程序。

謝謝你的幫助!

您的代碼中有多個問題:

  • blockAdd中,如果href->next_ NULL else分支中的 NULL,則您無法更新href->next_->previouse_

  • findLagerSize應更改為findLargerSize並應使用size + sizeof(block)來定位 memory 的適當塊。

  • allocateMemory也不正確:傳遞給sbrk的大小應該包括sizeof(block)額外字節,因此分配的塊應該插入堆中,如果它大於size + sizeof(block)則應該拆分。

  • freeList中,如果checkAllFree()返回 true,您應該調用brk(head) ,而不是brk(ptr)

  • merge中,您沒有正確更新href->size :您應該合並大小。 此外,您不會更新href-_next->previouse_

  • shrinkHeap的原型應該有一個返回類型和一個參數列表:

     void shrinkHeap(void)
  • shrinkHeap ,您必須在調用brk之前更新鏈接,因為調用后指針可能會變得無效。 此外,您必須測試href->previouse_是否不是NULL ,此更新可以簡化為:

     if (href->previouse_;= NULL) href->previouse_->next_ = NULL;
  • 您的malloc function 有一個缺陷: return new_list + sizeof(block); 不返回指向分配塊的指針,而是返回一個更遠的指針,導致應用程序寫入超出分配塊的末尾,可能會破壞競技場。 此外,free 計算的指針不指向block ,即使程序沒有寫入 memory 塊並調用未定義的行為,也會導致 arena 進一步損壞。

    malloc()的兩個地方,您應該改為:

     return new_list + 1;
  • 同樣在free()中,但不一定會導致錯誤,您應該避免對void指針執行算術運算,將它們轉換為unsigned char *用於可移植代碼:

     block *pref = (void *)((unsigned char*)ptr - sizeof(block));

    或在正確鍵入后執行算術:

     block *pref = ptr; ptr -= 1;

這是修改后的版本:

static struct list *head = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

typedef struct list {
    size_t size_;           // block size, including header
    int free_;              // free indicator, true or false
    struct list *next_;
    struct list *previouse_;
} block;

void blockAdd(block *href, size_t size) {
    href->free_ = FALSE;
    href->size_ = size + sizeof(block);
    href->next_ = NULL;
    href->previouse_ = NULL;

    if (!head || head > href) {
        if (head) {
            head->previouse_ = href;
        }
        href->next_ = head;
        head = href;
    } else {
        block *current = head;
        while (current->next_ && current->next_ < href) {
            current = current->next_;
        }
        href->next_ = current->next_;
        if (href->next_) {
            href->next_->previouse_ = href;
        }
        href->previouse_ = current;
        current->next_ = href;
    }
}

void *findExactSizeMatch(size_t size) {
    block *href = head;
    size_t t = size + sizeof(block);

    while (href) {
        if (href->free_ && href->size_ == t) {
            href->free_ = FALSE;
            return href;
        }
        href = href->next_;
    }
    return NULL;
}

void *findLargerBlock(size_t size) {
    block *href = head;
    size_t t = size + sizeof(block);

    while (href) {
        if (href->free_ && href->size_ > t) {
            return split(href, size);
        }
        href = href->next_;
    }
    return NULL;
}

void *allocateMemory(size_t size) {
    /* should add size of `block` */
    block *new_block = sbrk(BLOCK_SIZE(size));

    if (new_block == SBRK_FAILED) {
        exit(1);
    }
    /* should split new_block if BLOCK_SIZE(size) > size */
    blockAdd(new_block, size);

    return new_block;
}

bool checkAllFree() {
    block *href = head;

    while (href) {
        if (!href->free_) {
            return FALSE;
        }
        href = href->next_;
    }
    return TRUE;
}

void freeList(block *ptr) {
    if (checkAllFree()) {
        if (brk(head) == BRK_FAILED) {
            exit(1);
        }
        head = NULL;
    }
}

void merge(void) {
    block *href = head;

    while (href && href->next_) {
        if (href->free_ && href->next_->free_) {
            href->size_ += href->next_->size_;
            href->next_ = href->next_->next_;
            href->next_->previouse_ = href;
        }
        href = href->next_;
    }
}

void shrinkHeap(void) {
    block *href = head;

    if (href) {
        while (href->next_) {
            href = href->next_;
        }
        if (href->free_) {
            if (href->previouse_ != NULL) {
                href->previouse_->next_ = NULL;
            }
            if (brk(href) == BRK_FAILED) {
                exit(1);
            }
        }
    }
}

void *malloc(size_t size) {
    if (!size) {
        return NULL;
    }
    pthread_mutex_lock(&mutex);

    block *new_list = findExactSizeMatch(size);
    if (new_list == NULL) {
        new_list = findLargerSize(size);
    }
    if (new_list == NULL) {
        new_list = allocateMemory(size);
    }
    pthread_mutex_unlock(&mutex);
    if (new_list)
        return new_list += 1;
    else
        return NULL;
}

void free(void *ptr) {
    if (!ptr || !head) {
        return;
    }
    pthread_mutex_lock(&mutex);

    block *pref = ptr;
    pref -= 1;
    pref->free_ = TRUE;

    freeList(pref);
    merge();
    shrinkHeap();

    pthread_mutex_unlock(&mutex);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM