You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 line
3.2KB

  1. /*
  2. * This file is a part of SMalloc.
  3. * SMalloc is MIT licensed.
  4. * Copyright (c) 2017 Andrey Rys.
  5. */
  6. #include "smalloc_i.h"
  7. /*
  8. * Please do NOT use this function directly or rely on it's presence.
  9. * It may go away in future SMalloc versions, or it's calling
  10. * signature may change. It is internal function, hence "_i" suffix.
  11. */
  12. void *sm_realloc_pool_i(struct smalloc_pool *spool, void *p, size_t n, int nomove)
  13. {
  14. struct smalloc_hdr *basehdr, *shdr, *dhdr;
  15. void *r;
  16. char *s;
  17. int found;
  18. size_t rsz, usz, x;
  19. uintptr_t tag;
  20. if (!smalloc_verify_pool(spool)) {
  21. errno = EINVAL;
  22. return NULL;
  23. }
  24. if (!p) return sm_malloc_pool(spool, n);
  25. if (!n && p) {
  26. sm_free_pool(spool, p);
  27. return NULL;
  28. }
  29. /* determine user size */
  30. shdr = USER_TO_HEADER(p);
  31. if (!smalloc_is_alloc(spool, shdr)) smalloc_UB(spool, p);
  32. usz = shdr->usz;
  33. rsz = shdr->rsz;
  34. /* newsize is lesser than allocated - truncate */
  35. if (n <= usz) {
  36. if (spool->do_zero) memset(p + n, 0, shdr->rsz - n);
  37. s = CHAR_PTR(HEADER_TO_USER(shdr));
  38. s += usz;
  39. memset(s, 0, HEADER_SZ);
  40. if (spool->do_zero) memset(s+HEADER_SZ, 0, rsz - usz);
  41. shdr->rsz = (n%HEADER_SZ)?(((n/HEADER_SZ)+1)*HEADER_SZ):n;
  42. shdr->usz = n;
  43. shdr->tag = tag = smalloc_mktag(shdr);
  44. s = CHAR_PTR(HEADER_TO_USER(shdr));
  45. s += shdr->usz;
  46. for (x = 0; x < sizeof(struct smalloc_hdr); x += sizeof(uintptr_t)) {
  47. tag = smalloc_uinthash(tag);
  48. memcpy(s+x, &tag, sizeof(uintptr_t));
  49. }
  50. memset(s+x, 0xff, shdr->rsz - shdr->usz);
  51. return p;
  52. }
  53. /* newsize is bigger than allocated, but there is free room - modify */
  54. if (n > usz && n <= rsz) {
  55. if (spool->do_zero) {
  56. s = CHAR_PTR(HEADER_TO_USER(shdr));
  57. s += usz;
  58. memset(s, 0, HEADER_SZ);
  59. }
  60. shdr->usz = n;
  61. shdr->tag = tag = smalloc_mktag(shdr);
  62. s = CHAR_PTR(HEADER_TO_USER(shdr));
  63. s += shdr->usz;
  64. for (x = 0; x < sizeof(struct smalloc_hdr); x += sizeof(uintptr_t)) {
  65. tag = smalloc_uinthash(tag);
  66. memcpy(s+x, &tag, sizeof(uintptr_t));
  67. }
  68. memset(s+x, 0xff, shdr->rsz - shdr->usz);
  69. return p;
  70. }
  71. /* newsize is bigger, larger than rsz but there are free blocks beyond - extend */
  72. basehdr = spool->pool; dhdr = shdr+(rsz/HEADER_SZ); found = 0;
  73. while (CHAR_PTR(dhdr)-CHAR_PTR(basehdr) < spool->pool_size) {
  74. x = CHAR_PTR(dhdr)-CHAR_PTR(shdr);
  75. if (smalloc_is_alloc(spool, dhdr))
  76. goto allocblock;
  77. if (n + HEADER_SZ <= x) {
  78. x -= HEADER_SZ;
  79. found = 1;
  80. goto outfound;
  81. }
  82. dhdr++;
  83. }
  84. outfound:
  85. /* write new numbers of same allocation */
  86. if (found) {
  87. if (spool->do_zero) {
  88. s = CHAR_PTR(HEADER_TO_USER(shdr));
  89. s += usz;
  90. memset(s, 0, HEADER_SZ);
  91. memset(s+HEADER_SZ, 0, rsz - usz);
  92. }
  93. shdr->rsz = x;
  94. shdr->usz = n;
  95. shdr->tag = tag = smalloc_mktag(shdr);
  96. s = CHAR_PTR(HEADER_TO_USER(shdr));
  97. s += shdr->usz;
  98. for (x = 0; x < sizeof(struct smalloc_hdr); x += sizeof(uintptr_t)) {
  99. tag = smalloc_uinthash(tag);
  100. memcpy(s+x, &tag, sizeof(uintptr_t));
  101. }
  102. memset(s+x, 0xff, shdr->rsz - shdr->usz);
  103. return p;
  104. }
  105. allocblock:
  106. /* newsize is bigger than allocated and no free space - move */
  107. if (nomove) {
  108. /* fail if user asked */
  109. errno = ERANGE;
  110. return NULL;
  111. }
  112. r = sm_malloc_pool(spool, n);
  113. if (!r) return NULL;
  114. memcpy(r, p, usz);
  115. sm_free_pool(spool, p);
  116. return r;
  117. }