summaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-12-08 15:28:25 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-12-08 15:28:25 -0200
commite663a24ab03a54fa221c20a793812e5c5ffdf94f (patch)
tree8fbd40f779f0eed29d46f26c07e1234fd5df8bae /ltable.c
parent40f823ec907fd725617e37199199b3ed424bd88c (diff)
downloadlua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.tar.gz
lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.tar.bz2
lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.zip
more freedom in handling memory-allocation errors (not all allocations
automatically raise an error), which allows fixing a bug when resizing a table.
Diffstat (limited to 'ltable.c')
-rw-r--r--ltable.c95
1 files changed, 63 insertions, 32 deletions
diff --git a/ltable.c b/ltable.c
index d1345009..85101a8a 100644
--- a/ltable.c
+++ b/ltable.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltable.c,v 2.127 2017/11/23 19:29:04 roberto Exp roberto $ 2** $Id: ltable.c,v 2.128 2017/12/07 18:59:52 roberto Exp roberto $
3** Lua tables (hash) 3** Lua tables (hash)
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -357,15 +357,6 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
357} 357}
358 358
359 359
360static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
361 unsigned int i;
362 luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
363 for (i=t->sizearray; i<size; i++)
364 setnilvalue(&t->array[i]);
365 t->sizearray = size;
366}
367
368
369/* 360/*
370** Creates an array for the hash part of a table with the given 361** Creates an array for the hash part of a table with the given
371** size, or reuses the dummy node if size is zero. 362** size, or reuses the dummy node if size is zero.
@@ -398,39 +389,79 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
398} 389}
399 390
400 391
401void luaH_resize (lua_State *L, Table *t, unsigned int nasize, 392/*
393** (Re)insert all elements from list 'nodes' into table 't'.
394*/
395static void reinsert(lua_State *L, Node *nodes, int nsize, Table *t) {
396 int j;
397 for (j = nsize - 1; j >= 0; j--) {
398 Node *old = nodes + j;
399 if (!ttisnil(gval(old))) {
400 /* doesn't need barrier/invalidate cache, as entry was
401 already present in the table */
402 TValue k;
403 getnodekey(L, &k, old);
404 setobjt2t(L, luaH_set(L, t, &k), gval(old));
405 }
406 }
407}
408
409
410/*
411** Resize table 't' for the new given sizes. Both allocations
412** (for the hash part and for the array part) can fail, which
413** creates some subtleties. If the first allocation, for the hash
414** part, fails, an error is raised and that is it. Otherwise,
415** copy the elements in the shrinking part of the array (if it
416** is shrinking) into the new hash. Then it reallocates the array part.
417** If that fails, it frees the new hash part and restores the old hash
418** part (to restore the original state of the table), and then raises
419** the allocation error. Otherwise, initialize the new part of the
420** array (if any) with nils and reinsert the elements in the old
421** hash back into the new parts of the table.
422*/
423void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
402 unsigned int nhsize) { 424 unsigned int nhsize) {
403 unsigned int i; 425 unsigned int i;
404 int j; 426 Node *oldnode = t->node; /* save old hash ... */
405 unsigned int oldasize = t->sizearray; 427 Node *oldlastfree = t->lastfree;
428 int oldlsizenode = t->lsizenode;
406 int oldhsize = allocsizenode(t); 429 int oldhsize = allocsizenode(t);
407 Node *nold = t->node; /* save old hash ... */ 430 unsigned int oldasize = t->sizearray;
408 if (nasize > oldasize) /* array part must grow? */ 431 TValue *newarray;
409 setarrayvector(L, t, nasize);
410 /* create new hash part with appropriate size */ 432 /* create new hash part with appropriate size */
411 setnodevector(L, t, nhsize); 433 setnodevector(L, t, nhsize);
412 if (nasize < oldasize) { /* array part must shrink? */ 434 if (newasize < oldasize) { /* will array shrink? */
413 t->sizearray = nasize; 435 /* re-insert into the hash the elements from vanishing slice */
414 /* re-insert elements from vanishing slice */ 436 t->sizearray = newasize; /* pretend array has new size */
415 for (i=nasize; i<oldasize; i++) { 437 for (i = newasize; i < oldasize; i++) {
416 if (!ttisnil(&t->array[i])) 438 if (!ttisnil(&t->array[i]))
417 luaH_setint(L, t, i + 1, &t->array[i]); 439 luaH_setint(L, t, i + 1, &t->array[i]);
418 } 440 }
419 /* shrink array */ 441 t->sizearray = oldasize; /* restore current size */
420 luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
421 } 442 }
422 /* re-insert elements from hash part */ 443 /* allocate new array */
423 for (j = oldhsize - 1; j >= 0; j--) { 444 newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
424 Node *old = nold + j; 445 if (newarray == NULL && newasize > 0) { /* allocation failed? */
425 if (!ttisnil(gval(old))) { 446 if (nhsize > 0) /* not the dummy node? */
426 /* doesn't need barrier/invalidate cache, as entry was 447 luaM_freearray(L, t->node, allocsizenode(t)); /* release new hash part */
427 already present in the table */ 448 t->node = oldnode; /* restore original hash part */
428 TValue k; getnodekey(L, &k, old); 449 t->lastfree = oldlastfree;
429 setobjt2t(L, luaH_set(L, t, &k), gval(old)); 450 t->lsizenode = oldlsizenode;
430 } 451 lua_assert(!isdummy(t) == (t->node != dummynode));
452 luaM_error(L); /* error with array unchanged */
431 } 453 }
454 /* allocation ok; initialize new part of the array */
455 t->array = newarray;
456 t->sizearray = newasize;
457 for (i = oldasize; i < newasize; i++)
458 setnilvalue(&t->array[i]);
459 /* re-insert elements from old hash part into new parts */
460 reinsert(L, oldnode, oldhsize, t);
461 /* free old hash */
432 if (oldhsize > 0) /* not the dummy node? */ 462 if (oldhsize > 0) /* not the dummy node? */
433 luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ 463 luaM_freearray(L, oldnode, cast(size_t, oldhsize));
464 lua_assert(!isdummy(t) == (t->node != dummynode));
434} 465}
435 466
436 467