diff options
Diffstat (limited to '')
-rw-r--r-- | lauxlib.c | 54 | ||||
-rw-r--r-- | testes/gc.lua | 3 | ||||
-rw-r--r-- | testes/locals.lua | 10 |
3 files changed, 40 insertions, 27 deletions
@@ -470,18 +470,27 @@ typedef struct UBox { | |||
470 | } UBox; | 470 | } UBox; |
471 | 471 | ||
472 | 472 | ||
473 | /* Resize the buffer used by a box. Optimize for the common case of | ||
474 | ** resizing to the old size. (For instance, __gc will resize the box | ||
475 | ** to 0 even after it was closed. 'pushresult' may also resize it to a | ||
476 | ** final size that is equal to the one set when the buffer was created.) | ||
477 | */ | ||
473 | static void *resizebox (lua_State *L, int idx, size_t newsize) { | 478 | static void *resizebox (lua_State *L, int idx, size_t newsize) { |
474 | void *ud; | ||
475 | lua_Alloc allocf = lua_getallocf(L, &ud); | ||
476 | UBox *box = (UBox *)lua_touserdata(L, idx); | 479 | UBox *box = (UBox *)lua_touserdata(L, idx); |
477 | void *temp = allocf(ud, box->box, box->bsize, newsize); | 480 | if (box->bsize == newsize) /* not changing size? */ |
478 | if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ | 481 | return box->box; /* keep the buffer */ |
479 | lua_pushliteral(L, "not enough memory"); | 482 | else { |
480 | lua_error(L); /* raise a memory error */ | 483 | void *ud; |
484 | lua_Alloc allocf = lua_getallocf(L, &ud); | ||
485 | void *temp = allocf(ud, box->box, box->bsize, newsize); | ||
486 | if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ | ||
487 | lua_pushliteral(L, "not enough memory"); | ||
488 | lua_error(L); /* raise a memory error */ | ||
489 | } | ||
490 | box->box = temp; | ||
491 | box->bsize = newsize; | ||
492 | return temp; | ||
481 | } | 493 | } |
482 | box->box = temp; | ||
483 | box->bsize = newsize; | ||
484 | return temp; | ||
485 | } | 494 | } |
486 | 495 | ||
487 | 496 | ||
@@ -526,15 +535,15 @@ static void newbox (lua_State *L) { | |||
526 | 535 | ||
527 | /* | 536 | /* |
528 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' | 537 | ** Compute new size for buffer 'B', enough to accommodate extra 'sz' |
529 | ** bytes. (The test for "not big enough" also gets the case when the | 538 | ** bytes plus one for a terminating zero. (The test for "not big enough" |
530 | ** computation of 'newsize' overflows.) | 539 | ** also gets the case when the computation of 'newsize' overflows.) |
531 | */ | 540 | */ |
532 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { | 541 | static size_t newbuffsize (luaL_Buffer *B, size_t sz) { |
533 | size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ | 542 | size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */ |
534 | if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ | 543 | if (l_unlikely(MAX_SIZET - sz - 1 < B->n)) /* overflow in (B->n + sz + 1)? */ |
535 | return luaL_error(B->L, "buffer too large"); | 544 | return luaL_error(B->L, "buffer too large"); |
536 | if (newsize < B->n + sz) /* not big enough? */ | 545 | if (newsize < B->n + sz + 1) /* not big enough? */ |
537 | newsize = B->n + sz; | 546 | newsize = B->n + sz + 1; |
538 | return newsize; | 547 | return newsize; |
539 | } | 548 | } |
540 | 549 | ||
@@ -594,9 +603,22 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { | |||
594 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | 603 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { |
595 | lua_State *L = B->L; | 604 | lua_State *L = B->L; |
596 | checkbufferlevel(B, -1); | 605 | checkbufferlevel(B, -1); |
597 | lua_pushlstring(L, B->b, B->n); | 606 | if (!buffonstack(B)) /* using static buffer? */ |
598 | if (buffonstack(B)) | 607 | lua_pushlstring(L, B->b, B->n); /* save result as regular string */ |
608 | else { /* reuse buffer already allocated */ | ||
609 | UBox *box = (UBox *)lua_touserdata(L, -1); | ||
610 | void *ud; | ||
611 | lua_Alloc allocf = lua_getallocf(L, &ud); /* function to free buffer */ | ||
612 | size_t len = B->n; /* final string length */ | ||
613 | char *s; | ||
614 | resizebox(L, -1, len + 1); /* adjust box size to content size */ | ||
615 | s = (char*)box->box; /* final buffer address */ | ||
616 | s[len] = '\0'; /* add ending zero */ | ||
617 | /* clear box, as 'lua_pushextlstring' will take control over buffer */ | ||
618 | box->bsize = 0; box->box = NULL; | ||
619 | lua_pushextlstring(L, s, len, allocf, ud); | ||
599 | lua_closeslot(L, -2); /* close the box */ | 620 | lua_closeslot(L, -2); /* close the box */ |
621 | } | ||
600 | lua_remove(L, -2); /* remove box or placeholder from the stack */ | 622 | lua_remove(L, -2); /* remove box or placeholder from the stack */ |
601 | } | 623 | } |
602 | 624 | ||
diff --git a/testes/gc.lua b/testes/gc.lua index 03093e34..3c928d7c 100644 --- a/testes/gc.lua +++ b/testes/gc.lua | |||
@@ -460,10 +460,7 @@ do -- tests for string keys in weak tables | |||
460 | a[string.rep("a", 2^22)] = 25 -- long string key -> number value | 460 | a[string.rep("a", 2^22)] = 25 -- long string key -> number value |
461 | a[string.rep("b", 2^22)] = {} -- long string key -> colectable value | 461 | a[string.rep("b", 2^22)] = {} -- long string key -> colectable value |
462 | a[{}] = 14 -- colectable key | 462 | a[{}] = 14 -- colectable key |
463 | assert(collectgarbage("count") > m + 2^13) -- 2^13 == 2 * 2^22 in KB | ||
464 | collectgarbage() | 463 | collectgarbage() |
465 | assert(collectgarbage("count") >= m + 2^12 and | ||
466 | collectgarbage("count") < m + 2^13) -- one key was collected | ||
467 | local k, v = next(a) -- string key with number value preserved | 464 | local k, v = next(a) -- string key with number value preserved |
468 | assert(k == string.rep("a", 2^22) and v == 25) | 465 | assert(k == string.rep("a", 2^22) and v == 25) |
469 | assert(next(a, k) == nil) -- everything else cleared | 466 | assert(next(a, k) == nil) -- everything else cleared |
diff --git a/testes/locals.lua b/testes/locals.lua index 2c48546d..090d846b 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -728,14 +728,8 @@ if rawget(_G, "T") then | |||
728 | -- first buffer was released by 'toclose' | 728 | -- first buffer was released by 'toclose' |
729 | assert(T.totalmem() - m <= extra) | 729 | assert(T.totalmem() - m <= extra) |
730 | 730 | ||
731 | -- error in creation of final string | 731 | -- userdata, buffer, final string |
732 | T.totalmem(m + 2 * lim + extra) | 732 | T.totalmem(m + 2*lim + extra) |
733 | assert(not pcall(table.concat, a)) | ||
734 | -- second buffer was released by 'toclose' | ||
735 | assert(T.totalmem() - m <= extra) | ||
736 | |||
737 | -- userdata, buffer, buffer, final string | ||
738 | T.totalmem(m + 4*lim + extra) | ||
739 | assert(#table.concat(a) == 2*lim) | 733 | assert(#table.concat(a) == 2*lim) |
740 | 734 | ||
741 | T.totalmem(0) -- remove memory limit | 735 | T.totalmem(0) -- remove memory limit |