简体   繁体   English

自己的 Malloc 实现冻结在 brk

[英]Own Malloc implementation freeze at brk

for practice I'm currently trying to write my own malloc function in c.为了练习,我目前正在尝试在 c 中编写自己的 malloc function。 So my question is, after some allocation from the heap my program will freeze.所以我的问题是,在从堆中进行一些分配后,我的程序将冻结。 I found the code segment which will couse the freeze and it'll freeze when i call the brk sys call.我找到了导致冻结的代码段,当我调用 brk sys 调用时它会冻结。 I allready tried to unlock my mutex there but this didn't work.我已经尝试在那里解锁我的互斥锁,但这没有用。 To test it i wrote a permanent loop and allocate memory in an array and freed it randomly.为了测试它,我编写了一个永久循环并在一个数组中分配 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);
}

I don't know why, but brk freeze my program.我不知道为什么,但是 brk 冻结了我的程序。

Thx for your help!谢谢你的帮助!

There are multiple problems in your code:您的代码中有多个问题:

  • in blockAdd , you fail to update href->next_->previouse_ if href->next_ is not NULL in the else branch.blockAdd中,如果href->next_ NULL else分支中的 NULL,则您无法更新href->next_->previouse_

  • findLagerSize should be changed to findLargerSize and should use size + sizeof(block) to locate an appropriate block of memory. findLagerSize应更改为findLargerSize并应使用size + sizeof(block)来定位 memory 的适当块。

  • allocateMemory is incorrect too: the size passed to sbrk should include sizeof(block) extra bytes, the block thus allocated should be inserted into the heap and split if it is larger than size + sizeof(block) . allocateMemory也不正确:传递给sbrk的大小应该包括sizeof(block)额外字节,因此分配的块应该插入堆中,如果它大于size + sizeof(block)则应该拆分。

  • in freeList , in case checkAllFree() returns true, you should call brk(head) , not brk(ptr) .freeList中,如果checkAllFree()返回 true,您应该调用brk(head) ,而不是brk(ptr)

  • in merge , you do not update href->size correctly: you should combine the sizes.merge中,您没有正确更新href->size :您应该合并大小。 Furthermore you do not upate href-_next->previouse_ .此外,您不会更新href-_next->previouse_

  • The prototype for shrinkHeap should have a return type and an argument list: shrinkHeap的原型应该有一个返回类型和一个参数列表:

     void shrinkHeap(void)
  • In shrinkHeap you must update the link before calling brk as the pointer may become invalid after the call.shrinkHeap ,您必须在调用brk之前更新链接,因为调用后指针可能会变得无效。 Furthermore, you must test if href->previouse_ is not NULL and this update can be simplified as:此外,您必须测试href->previouse_是否不是NULL ,此更新可以简化为:

     if (href->previouse_;= NULL) href->previouse_->next_ = NULL;
  • Your malloc function has a flaw: return new_list + sizeof(block);您的malloc function 有一个缺陷: return new_list + sizeof(block); does not return the pointer to the allocated block, but one much farther away, causing the application to write beyond the end of the allocated block, potentially corrupting the arena.不返回指向分配块的指针,而是返回一个更远的指针,导致应用程序写入超出分配块的末尾,可能会破坏竞技场。 Furthermore, the pointer computed by free does not point to the block , causing further corruption of the arena even if the program did not write to the memory block and invoking undefined behavior.此外,free 计算的指针不指向block ,即使程序没有写入 memory 块并调用未定义的行为,也会导致 arena 进一步损坏。

    In both places in malloc() , you should write this instead:malloc()的两个地方,您应该改为:

     return new_list + 1;
  • Similarly in free() , but not necessarily causing an error, you should avoid performing arithmetics on void pointers, cast them as unsigned char * for portable code:同样在free()中,但不一定会导致错误,您应该避免对void指针执行算术运算,将它们转换为unsigned char *用于可移植代码:

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

    Or perform the arithmetics after proper typing:或在正确键入后执行算术:

     block *pref = ptr; ptr -= 1;

Here is a modified version:这是修改后的版本:

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