File: alloc.c

package info (click to toggle)
php-luasandbox 4.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 620 kB
  • sloc: ansic: 3,700; xml: 2,152; php: 64; makefile: 13; sh: 3
file content (116 lines) | stat: -rw-r--r-- 2,821 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
 * The Lua allocator hook
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include <limits.h>

#include "php.h"
#include "php_luasandbox.h"

static inline int luasandbox_update_memory_accounting(php_luasandbox_alloc * obj,
	size_t osize, size_t nsize);
static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize);

lua_State * luasandbox_alloc_new_state(php_luasandbox_alloc * alloc, php_luasandbox_obj * sandbox)
{
	lua_State * L;
	L = lua_newstate(luasandbox_php_alloc, sandbox);
	return L;
}

void luasandbox_alloc_delete_state(php_luasandbox_alloc * alloc, lua_State * L)
{
	lua_close(L);
}


/** {{{ luasandbox_update_memory_accounting
 *
 * Update memory usage statistics for the given memory allocation request.
 * Returns 1 if the allocation should be allowed, 0 if it should fail.
 */
static inline int luasandbox_update_memory_accounting(php_luasandbox_alloc * alloc,
	size_t osize, size_t nsize)
{
	if (nsize > osize && (nsize > alloc->memory_limit
		|| alloc->memory_usage + nsize > alloc->memory_limit))
	{
		// Memory limit exceeded
		return 0;
	}

	if (osize > nsize && alloc->memory_usage + nsize < osize) {
		// Negative memory usage -- do not update
		return 1;
	}

	alloc->memory_usage += nsize - osize;
	if (alloc->memory_usage > alloc->peak_memory_usage) {
		alloc->peak_memory_usage = alloc->memory_usage;
	}
	return 1;
}
/* }}} */

/** {{{ luasandbox_update_gc_pause
 * Scale the GC pause size so that collection will start before an OOM occurs (T349462)
 */
static inline void luasandbox_update_gc_pause(lua_State * L, php_luasandbox_alloc * alloc)
{
	size_t limit = alloc->memory_limit;
	size_t usage = alloc->memory_usage;

	// Guard against overflow and division by zero
	if (limit >= SIZE_MAX / 90 || usage == 0) {
		return;
	}
	size_t pause = limit * 90 / usage;
	if (pause > 200) {
		pause = 200;
	}
	lua_gc(L, LUA_GCSETPAUSE, (int)pause);
}
/* }}} */

/** {{{ luasandbox_php_alloc
 *
 * The Lua allocator function. Use PHP's request-local allocator as a backend.
 * Account for memory usage and deny the allocation request if the amount
 * allocated is above the user-specified limit.
 */
static void *luasandbox_php_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
	php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
	void * nptr;
	obj->in_php ++;
	if (!luasandbox_update_memory_accounting(&obj->alloc, osize, nsize)) {
		obj->in_php --;
		return NULL;
	}

	luasandbox_update_gc_pause(obj->state, &obj->alloc);

	if (nsize == 0) {
		if (ptr) {
			efree(ptr);
		}
		nptr = NULL;
	} else if (osize == 0) {
		nptr = ecalloc(1, nsize);
	} else {
		nptr = erealloc(ptr, nsize);
		if (nsize > osize) {
			memset(nptr + osize, 0, nsize - osize);
		}
	}
	obj->in_php --;
	return nptr;
}
/* }}} */