LCOV - code coverage report
Current view: top level - src - alloc.c (source / functions) Hit Total Coverage
Test: mediawiki/php/luasandbox test coverage report Lines: 42 43 97.7 %
Date: 2023-12-12 07:35:14 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /**
       2             :  * The Lua allocator hook
       3             :  */
       4             : 
       5             : #ifdef HAVE_CONFIG_H
       6             : #include "config.h"
       7             : #endif
       8             : 
       9             : #include <lua.h>
      10             : #include <lauxlib.h>
      11             : #include <string.h>
      12             : #include <limits.h>
      13             : 
      14             : #include "php.h"
      15             : #include "php_luasandbox.h"
      16             : 
      17             : static inline int luasandbox_update_memory_accounting(php_luasandbox_alloc * obj,
      18             :     size_t osize, size_t nsize);
      19             : static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
      20             : 
      21         126 : lua_State * luasandbox_alloc_new_state(php_luasandbox_alloc * alloc, php_luasandbox_obj * sandbox)
      22             : {
      23             :     lua_State * L;
      24         126 :     L = lua_newstate(luasandbox_php_alloc, sandbox);
      25         126 :     return L;
      26             : }
      27             : 
      28         125 : void luasandbox_alloc_delete_state(php_luasandbox_alloc * alloc, lua_State * L)
      29             : {
      30         125 :     lua_close(L);
      31         125 : }
      32             : 
      33             : 
      34             : /** {{{ luasandbox_update_memory_accounting
      35             :  *
      36             :  * Update memory usage statistics for the given memory allocation request.
      37             :  * Returns 1 if the allocation should be allowed, 0 if it should fail.
      38             :  */
      39      298305 : static inline int luasandbox_update_memory_accounting(php_luasandbox_alloc * alloc,
      40             :     size_t osize, size_t nsize)
      41             : {
      42      298305 :     if (nsize > osize && (nsize > alloc->memory_limit
      43      115414 :         || alloc->memory_usage + nsize > alloc->memory_limit))
      44             :     {
      45             :         // Memory limit exceeded
      46           9 :         return 0;
      47             :     }
      48             : 
      49      298296 :     if (osize > nsize && alloc->memory_usage + nsize < osize) {
      50             :         // Negative memory usage -- do not update
      51           0 :         return 1;
      52             :     }
      53             : 
      54      298296 :     alloc->memory_usage += nsize - osize;
      55      298296 :     if (alloc->memory_usage > alloc->peak_memory_usage) {
      56       39041 :         alloc->peak_memory_usage = alloc->memory_usage;
      57             :     }
      58      298296 :     return 1;
      59             : }
      60             : /* }}} */
      61             : 
      62             : /** {{{ luasandbox_update_gc_pause
      63             :  * Scale the GC pause size so that collection will start before an OOM occurs (T349462)
      64             :  */
      65      298296 : static inline void luasandbox_update_gc_pause(lua_State * L, php_luasandbox_alloc * alloc)
      66             : {
      67      298296 :     size_t limit = alloc->memory_limit;
      68      298296 :     size_t usage = alloc->memory_usage;
      69             : 
      70             :     // Guard against overflow and division by zero
      71      298296 :     if (limit >= SIZE_MAX / 90 || usage == 0) {
      72      264299 :         return;
      73             :     }
      74       33997 :     size_t pause = limit * 90 / usage;
      75       33997 :     if (pause > 200) {
      76       32899 :         pause = 200;
      77             :     }
      78       33997 :     lua_gc(L, LUA_GCSETPAUSE, (int)pause);
      79             : }
      80             : /* }}} */
      81             : 
      82             : /** {{{ luasandbox_php_alloc
      83             :  *
      84             :  * The Lua allocator function. Use PHP's request-local allocator as a backend.
      85             :  * Account for memory usage and deny the allocation request if the amount
      86             :  * allocated is above the user-specified limit.
      87             :  */
      88      298305 : static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
      89             : {
      90      298305 :     php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
      91             :     void * nptr;
      92      298305 :     obj->in_php ++;
      93      298305 :     if (!luasandbox_update_memory_accounting(&obj->alloc, osize, nsize)) {
      94           9 :         obj->in_php --;
      95           9 :         return NULL;
      96             :     }
      97             : 
      98      298296 :     luasandbox_update_gc_pause(obj->state, &obj->alloc);
      99             : 
     100      298296 :     if (nsize == 0) {
     101      181483 :         if (ptr) {
     102      112524 :             efree(ptr);
     103             :         }
     104      181483 :         nptr = NULL;
     105      116813 :     } else if (osize == 0) {
     106      112760 :         nptr = ecalloc(1, nsize);
     107             :     } else {
     108        4053 :         nptr = erealloc(ptr, nsize);
     109        4053 :         if (nsize > osize) {
     110        2645 :             memset(nptr + osize, 0, nsize - osize);
     111             :         }
     112             :     }
     113      298295 :     obj->in_php --;
     114      298295 :     return nptr;
     115             : }
     116             : /* }}} */

Generated by: LCOV version 1.13