Skip to content

Commit 9aa729c

Browse files
committed
2.2.0
1 parent 6d1996d commit 9aa729c

File tree

8 files changed

+454
-30
lines changed

8 files changed

+454
-30
lines changed

lib/JavaScript/Duktape.pm

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use warnings;
44
use Carp;
55
use Data::Dumper;
66
use Scalar::Util qw( weaken );
7-
our $VERSION = '2.1.5';
7+
our $VERSION = '2.2.0';
88

99
my $GlobalRef = {};
1010

@@ -131,9 +131,21 @@ use constant {
131131

132132
sub new {
133133
my $class = shift;
134+
my %options = @_;
135+
136+
my $max_memory = $options{max_memory} || 0;
137+
138+
if ( $max_memory ){
139+
croak "max_memory option should be a number" if !JavaScript::Duktape::Vm::duk_sv_is_number( $max_memory );
140+
croak "max_memory must be at least 256k (256 * 1024)" if $max_memory < 256 * 1024;
141+
}
142+
134143
my $self = bless {}, $class;
135-
my $duk = $self->{duk} = JavaScript::Duktape::Vm->perl_duk_new();
144+
145+
my $duk = $self->{duk} = JavaScript::Duktape::Vm->perl_duk_new( $max_memory );
146+
136147
$self->{pid} = $$;
148+
$self->{max_memory} = $max_memory;
137149

138150
# Initialize global stash 'PerlGlobalStash'
139151
# this will be used to store some perl refs
@@ -240,17 +252,28 @@ sub eval {
240252
sub vm { shift->{duk}; }
241253
sub duk { shift->{duk}; }
242254

255+
sub set_timeout {
256+
my $self = shift;
257+
$self->duk->set_timeout( shift );
258+
}
259+
260+
sub resize_memory {
261+
my $self = shift;
262+
$self->duk->resize_memory( shift );
263+
}
264+
243265
sub destroy {
244266
local $@;
245267
my $self = shift;
246268
my $duk = delete $self->{duk};
247269
return if !$duk;
270+
$duk->free_perl_duk();
248271
$duk->destroy_heap();
249272
}
250273

251274
sub DESTROY {
252275
my $self = shift;
253-
if ( $self->{pid} == $$ ) {
276+
if ( $self->{pid} && $self->{pid} == $$ ) {
254277
$self->destroy();
255278
}
256279
}
@@ -278,11 +301,11 @@ BEGIN {
278301
: _get_path('duktape.so');
279302
}
280303

281-
use Inline C => config => typemaps => _get_path('typemap'),
282-
INC => '-I' . _get_path('../C') . ' -I' . _get_path('../C/lib');
283-
284-
# myextlib => $Duklib,
285-
# LIBS => '-L'. JavaScript::Duktape::C::libPath::getPath('../C') . ' -lduktape';
304+
use Inline C => config =>
305+
typemaps => _get_path('typemap'),
306+
INC => '-I' . _get_path('../C') . ' -I' . _get_path('../C/lib');
307+
# myextlib => $Duklib,
308+
# LIBS => '-L'. _get_path('../C/lib') . ' -lduktape';
286309

287310
use Inline C => _get_path('duk_perl.c');
288311

@@ -610,6 +633,24 @@ sub safe_call {
610633
return defined $ret ? $ret : 1;
611634
}
612635

636+
sub set_timeout {
637+
my $self = shift;
638+
my $timeout = shift;
639+
640+
croak "timeout must be a number" if !duk_sv_is_number($timeout);
641+
$self->perl_duk_set_timeout($timeout);
642+
}
643+
644+
sub resize_memory {
645+
my $self = shift;
646+
my $max_memory = shift || 0;
647+
648+
croak "max_memory should be a number" if !duk_sv_is_number( $max_memory );
649+
croak "max_memory must be at least 256k (256 * 1024)" if $max_memory < 256 * 1024;
650+
651+
$self->perl_duk_resize_memory($max_memory);
652+
}
653+
613654
##############################################
614655
# custom functions
615656
##############################################

lib/JavaScript/Duktape/C/duk_perl.c

Lines changed: 206 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
#include "perl.h"
66
#include "XSUB.h"
77
#include "ppport.h"
8+
#include <time.h>
9+
#include <stdlib.h>
810

911
#define NEED_newRV_noinc
1012
#define DUKTAPE_DONT_LOAD_SHARED
1113

14+
1215
#include "./lib/duktape.c"
1316
#include "./lib/module-duktape/duk_module_duktape.c"
1417
#include "./lib/print-alert/duk_print_alert.c"
@@ -20,23 +23,150 @@
2023

2124

2225

26+
typedef struct {
27+
/* The double value in the union is there to ensure alignment is
28+
* good for IEEE doubles too. In many 32-bit environments 4 bytes
29+
* would be sufficiently aligned and the double value is unnecessary.
30+
*/
31+
union {
32+
size_t sz;
33+
double d;
34+
} u;
35+
} perlDukMemHdr;
36+
37+
typedef struct {
38+
int timeout;
39+
size_t max_memory;
40+
size_t total_allocated;
41+
duk_context *ctx;
42+
} perlDuk;
43+
44+
45+
2346
/**
24-
* dump_stack
25-
* for debugging
47+
* perl_duk_exec_timeout
2648
******************************************************************************/
27-
int dump_stack(duk_context *ctx, const char *name) {
28-
duk_idx_t i, n;
29-
n = duk_get_top(ctx);
30-
printf("%s (top=%ld):", name, (long) n);
31-
for (i = 0; i < n; i++) {
32-
printf(" ");
33-
duk_dup(ctx, i);
34-
printf("%s", duk_safe_to_string(ctx, -1));
35-
duk_pop(ctx);
49+
int perl_duk_exec_timeout( void *udata ) {
50+
perlDuk *duk = (perlDuk *) udata;
51+
int timeout = duk->timeout;
52+
53+
if (timeout > 0){
54+
clock_t uptime = clock();
55+
int passed_time = (int)(uptime / CLOCKS_PER_SEC);
56+
if (passed_time > timeout){
57+
return 1;
58+
}
3659
}
37-
printf("\n");
38-
fflush(stdout);
39-
return 1;
60+
return 0;
61+
}
62+
63+
64+
65+
/**
66+
* duk_sandbox_alloc
67+
******************************************************************************/
68+
static void *duk_sandbox_alloc(void *udata, duk_size_t size) {
69+
perlDuk *duk = (perlDuk *) udata;
70+
perlDukMemHdr *hdr;
71+
72+
size_t max_memory = duk->max_memory;
73+
size_t total_allocated = duk->total_allocated;
74+
75+
if (size == 0) return NULL;
76+
77+
if (total_allocated + size >= max_memory) {
78+
duk->total_allocated = 0;
79+
return NULL;
80+
}
81+
82+
hdr = (perlDukMemHdr *) malloc(size + sizeof(perlDukMemHdr));
83+
if (!hdr) return NULL;
84+
85+
hdr->u.sz = size;
86+
duk->total_allocated += size;
87+
return (void *) (hdr + 1);
88+
}
89+
90+
91+
92+
/**
93+
* duk_sandbox_realloc
94+
******************************************************************************/
95+
static void *duk_sandbox_realloc(void *udata, void *ptr, duk_size_t size) {
96+
perlDukMemHdr *hdr;
97+
size_t old_size;
98+
void *t;
99+
100+
perlDuk *duk = (perlDuk *) udata;
101+
size_t max_memory = duk->max_memory;
102+
size_t total_allocated = duk->total_allocated;
103+
104+
if (ptr) {
105+
hdr = (perlDukMemHdr *) (((char *) ptr) - sizeof(perlDukMemHdr));
106+
old_size = hdr->u.sz;
107+
108+
if (size == 0) {
109+
duk->total_allocated -= old_size;
110+
free((void *) hdr);
111+
return NULL;
112+
}
113+
114+
if (total_allocated - old_size + size > max_memory) {
115+
duk->total_allocated = 0;
116+
return NULL;
117+
}
118+
119+
t = realloc((void *) hdr, size + sizeof(perlDukMemHdr));
120+
if (!t) return NULL;
121+
122+
hdr = (perlDukMemHdr *) t;
123+
duk->total_allocated -= old_size;
124+
duk->total_allocated += size;
125+
hdr->u.sz = size;
126+
return (void *) (hdr + 1);
127+
} else {
128+
if (size == 0) return NULL;
129+
130+
if (total_allocated + size > max_memory) {
131+
duk->total_allocated = 0;
132+
return NULL;
133+
}
134+
135+
hdr = (perlDukMemHdr *) malloc(size + sizeof(perlDukMemHdr));
136+
if (!hdr) return NULL;
137+
138+
hdr->u.sz = size;
139+
duk->total_allocated += size;
140+
return (void *) (hdr + 1);
141+
}
142+
}
143+
144+
145+
146+
/**
147+
* duk_sandbox_free
148+
******************************************************************************/
149+
static void duk_sandbox_free(void *udata, void *ptr) {
150+
perlDukMemHdr *hdr;
151+
152+
perlDuk *duk = (perlDuk *) udata;
153+
154+
if (!ptr) return;
155+
156+
hdr = (perlDukMemHdr *) (((char *) ptr) - sizeof(perlDukMemHdr));
157+
duk->total_allocated -= hdr->u.sz;
158+
free((void *) hdr);
159+
}
160+
161+
162+
163+
/**
164+
* get_user_data
165+
******************************************************************************/
166+
perlDuk *get_user_data (duk_context *ctx){
167+
duk_memory_functions funcs;
168+
duk_get_memory_functions(ctx, &funcs);
169+
return (perlDuk *)funcs.udata;
40170
}
41171

42172

@@ -53,12 +183,23 @@ void fatal_handler (void *udata, const char *msg) {
53183
/**
54184
* new
55185
******************************************************************************/
56-
SV *perl_duk_new(const char * classname) {
186+
SV *perl_duk_new(const char *classname, size_t max_memory) {
57187
duk_context *ctx;
58-
SV *obj;
59-
SV *obj_ref;
188+
SV *obj;
189+
SV *obj_ref;
190+
191+
perlDuk *duk = malloc(sizeof(*duk));
192+
duk->ctx = NULL;
193+
duk->timeout = 0;
194+
duk->max_memory = max_memory;
195+
duk->total_allocated = 0;
196+
197+
if (max_memory > 0){
198+
ctx = duk_create_heap(duk_sandbox_alloc, duk_sandbox_realloc, duk_sandbox_free, (void *)duk, fatal_handler);
199+
} else {
200+
ctx = duk_create_heap(NULL, NULL, NULL, (void *)duk, fatal_handler);
201+
}
60202

61-
ctx = duk_create_heap(NULL, NULL, NULL, NULL, fatal_handler);
62203
duk_module_duktape_init(ctx);
63204
duk_print_alert_init(ctx, 0);
64205

@@ -67,11 +208,38 @@ SV *perl_duk_new(const char * classname) {
67208
sv_bless(obj_ref, gv_stashpv(classname, GV_ADD));
68209
SvREADONLY_on(obj);
69210

211+
duk->ctx = ctx;
70212
return obj_ref;
71213
}
72214

73215

74216

217+
/**
218+
* perl_duk_set_timeout
219+
******************************************************************************/
220+
void perl_duk_set_timeout(duk_context *ctx, int timeout){
221+
perlDuk *duk = get_user_data(ctx);
222+
int current = 0;
223+
224+
if (timeout > 0){
225+
timeout += (int)(clock() / CLOCKS_PER_SEC);
226+
}
227+
228+
duk->timeout = current + timeout;
229+
}
230+
231+
232+
233+
/**
234+
* perl_duk_resize_memory
235+
******************************************************************************/
236+
void perl_duk_resize_memory(duk_context *ctx, size_t max_memory){
237+
perlDuk *duk = get_user_data(ctx);
238+
duk->max_memory = max_memory;
239+
}
240+
241+
242+
75243
/**
76244
* perl_duk_reset_top
77245
* quick helper function to reset stack top
@@ -81,16 +249,18 @@ void perl_duk_reset_top(duk_context *ctx){
81249
duk_pop_n(ctx, top);
82250
}
83251

252+
253+
84254
/**
85255
* is number
86256
******************************************************************************/
87257
int duk_sv_is_number(SV *sv) {
88-
if (SvIOK(sv) || SvNOK(sv)){
89-
return 1;
90-
}
258+
if (SvIOK(sv) || SvNOK(sv)) return 1;
91259
return 0;
92260
}
93261

262+
263+
94264
/**
95265
* call_safe_perl_sub
96266
******************************************************************************/
@@ -273,11 +443,25 @@ int duktape_dlClose(duk_context *ctx, void *dlHandle){
273443
}
274444

275445

446+
447+
/**
448+
* destructions
449+
******************************************************************************/
450+
void free_perl_duk (duk_context *ctx){
451+
perlDuk *duk = get_user_data(ctx);
452+
if (duk != NULL) free(duk);
453+
}
454+
455+
456+
// not callabel
276457
void DESTROY(duk_context *ctx) {
458+
perlDuk *duk = get_user_data(ctx);
459+
if (duk != NULL) free(duk);
277460
printf("Destroying %p\n", ctx);
278-
//Safefree(ctx);
279461
}
280462

463+
464+
281465
/*
282466
Auto Generated C Code by parser.pl
283467
parser.pl reads duktape.h file and create both

0 commit comments

Comments
 (0)