ClamAV is an open source (GPLv2) anti-virus toolkit.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
clamav/libclamav/js/b_file.c

1018 lines
24 KiB

/*
* The builtin File object.
* Copyright (c) 1998-1999 New Generation Software (NGS) Oy
*
* Author: Markku Rossi <mtr@ngs.fi>
*/
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*/
/*
* $Source: /tmp/cvsroot-15-2-2007/clamav-devel/libclamav/js/b_file.c,v $
* $Id: b_file.c,v 1.2 2006/10/28 11:27:44 njh Exp $
*/
/*
* Static methods.
*
* byteToString (BYTE) => string
* + chmod (string, int) => boolean
* + lstat (PATH) => array / boolean
* + remove (PATH) => boolean
* + rename (FROM, TO) => boolean
* + stat (PATH) => array / boolean
* stringToByte (STRING) => number
*
* Methods:
*
* open (MODE) => boolean
* close () => boolean
* setPosition (POSITION [, WHENCE]) => boolean
* getPosition () => integer
* eof () => boolean
* read (SIZE) => string
* readln () => string
* readByte () => integer
* write (STRING) => boolean
* writeln (STRING) => boolean
* writeByte (INTEGER) => boolean
* + ungetByte (BYTE) => boolean
* flush () => boolean
* getLength () => integer
* exists () => boolean
* error () => integer
* clearError () => true
*
* Properties:
*
* autoFlush boolean mutable
* bufferSize integer mutable
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#ifdef CL_EXPERIMENTAL
#include "jsint.h"
#include <sys/stat.h>
/*
* Types and definitions.
*/
#define INSECURE() \
do { \
if (secure_mode) \
goto insecure_feature; \
} while (0)
/* Class context. */
struct file_ctx_st
{
/* Static methods. */
JSSymbol s_byteToString;
JSSymbol s_chmod;
JSSymbol s_lstat;
JSSymbol s_remove;
JSSymbol s_rename;
JSSymbol s_stat;
JSSymbol s_stringToByte;
/* Methods */
JSSymbol s_open;
JSSymbol s_close;
JSSymbol s_setPosition;
JSSymbol s_getPosition;
JSSymbol s_eof;
JSSymbol s_read;
JSSymbol s_readln;
JSSymbol s_readByte;
JSSymbol s_write;
JSSymbol s_writeln;
JSSymbol s_writeByte;
JSSymbol s_ungetByte;
JSSymbol s_flush;
JSSymbol s_getLength;
JSSymbol s_exists;
JSSymbol s_error;
JSSymbol s_clearError;
/* Properties. */
JSSymbol s_autoFlush;
JSSymbol s_bufferSize;
};
typedef struct file_ctx_st FileCtx;
/* Instance context. */
struct file_instance_ctx_st
{
/* Flags. */
unsigned int dont_close : 1;
char *path;
JSIOStream *stream;
/* Needed for the delete_proc. */
JSVirtualMachine *vm;
};
typedef struct file_instance_ctx_st FileInstanceCtx;
/*
* Static functions.
*/
/* Method proc. */
static int
method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
void *instance_context, JSSymbol method, JSNode *result_return,
JSNode *args)
{
FileCtx *ctx = builtin_info->obj_context;
FileInstanceCtx *ictx = instance_context;
char buf[256];
long int li = 0;
int i = 0;
char *cp;
int secure_mode = vm->security & JS_VM_SECURE_FILE;
/* The default result is false. */
result_return->type = JS_BOOLEAN;
result_return->u.vboolean = 0;
/*
* Static methods.
*/
if (method == ctx->s_byteToString)
{
if (args->u.vinteger != 1)
goto argument_error;
i = -1;
if (args[1].type == JS_INTEGER)
{
i = args[1].u.vinteger;
if (i < 0 || i > 255)
i = -1;
}
js_vm_make_string (vm, result_return, NULL, 1);
if (i < 0)
result_return->u.vstring->len = 0;
else
result_return->u.vstring->data[0] = i;
}
/* ********************************************************************** */
else if (method == ctx->s_chmod)
{
INSECURE ();
if (args->u.vinteger != 2)
goto argument_error;
if (args[1].type != JS_STRING)
goto argument_type_error;
if (args[2].type != JS_INTEGER)
goto argument_type_error;
result_return->type= JS_BOOLEAN;
cp = js_string_to_c_string (vm, &args[1]);
result_return->u.vboolean = (chmod (cp, args[2].u.vinteger) == 0);
js_free (cp);
}
/* ********************************************************************** */
else if (method == ctx->s_lstat || method == ctx->s_stat)
{
char *path;
struct stat stat_st;
int result;
INSECURE ();
if (args->u.vinteger != 1)
goto argument_error;
path = js_string_to_c_string (vm, &args[1]);
#if HAVE_LSTAT
if (method == ctx->s_lstat)
result = lstat (path, &stat_st);
else
#endif /* HAVE_LSTAT */
result = stat (path, &stat_st);
js_free (path);
if (result >= 0)
{
JSNode *node;
/* Success. */
js_vm_make_array (vm, result_return, 13);
node = result_return->u.varray->data;
/* dev */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_dev;
node++;
/* ino */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_ino;
node++;
/* mode */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_mode;
node++;
/* nlink */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_nlink;
node++;
/* uid */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_uid;
node++;
/* gid */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_gid;
node++;
/* rdev */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_rdev;
node++;
/* size */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_size;
node++;
/* atime */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_atime;
node++;
/* mtime */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_mtime;
node++;
/* ctime */
node->type = JS_INTEGER;
node->u.vinteger = stat_st.st_ctime;
node++;
/* blksize */
node->type = JS_INTEGER;
#if HAVE_STAT_ST_ST_BLKSIZE
node->u.vinteger = stat_st.st_blksize;
#else /* not HAVE_STAT_ST_ST_BLKSIZE */
node->u.vinteger = 0;
#endif /* not HAVE_STAT_ST_ST_BLKSIZE */
node++;
/* blocks */
node->type = JS_INTEGER;
#if HAVE_STAT_ST_ST_BLOCKS
node->u.vinteger = stat_st.st_blocks;
#else /* not HAVE_STAT_ST_ST_BLOCKS */
node->u.vinteger = 0;
#endif /* not HAVE_STAT_ST_ST_BLOCKS */
}
}
/* ********************************************************************** */
else if (method == ctx->s_remove)
{
char *path;
INSECURE ();
if (args->u.vinteger != 1)
goto argument_error;
if (args[1].type != JS_STRING)
goto argument_type_error;
path = js_string_to_c_string (vm, &args[1]);
i = remove (path);
js_free (path);
result_return->u.vboolean = (i == 0);
}
/* ********************************************************************** */
else if (method == ctx->s_rename)
{
char *path1;
char *path2;
INSECURE ();
if (args->u.vinteger != 2)
goto argument_error;
if (args[1].type != JS_STRING || args[2].type != JS_STRING)
goto argument_type_error;
path1 = js_string_to_c_string (vm, &args[1]);
path2 = js_string_to_c_string (vm, &args[2]);
i = rename (path1, path2);
js_free (path1);
js_free (path2);
result_return->u.vboolean = (i == 0);
}
/* ********************************************************************** */
else if (method == ctx->s_stringToByte)
{
if (args->u.vinteger != 1)
goto argument_error;
result_return->type = JS_INTEGER;
if (args[1].type == JS_STRING && args[1].u.vstring->len > 0)
result_return->u.vinteger = args[i].u.vstring->data[0];
else
result_return->u.vinteger = 0;
}
/* ********************************************************************** */
else if (method == vm->syms.s_toString)
{
if (args->u.vinteger != 0)
goto argument_error;
if (ictx)
js_vm_make_string (vm, result_return, ictx->path, strlen (ictx->path));
else
js_vm_make_static_string (vm, result_return, "File", 4);
}
/* ********************************************************************** */
else if (ictx)
{
/*
* Instance methods.
*/
if (method == ctx->s_open)
{
int readp = 0;
int writep = 0;
INSECURE ();
if (args->u.vinteger != 1)
goto argument_error;
if (args[1].type != JS_STRING
|| args[1].u.vstring->len == 0
|| args[1].u.vstring->len > 3)
goto argument_type_error;
i = args[1].u.vstring->len;
memcpy (buf, args[1].u.vstring->data, i);
if (buf[i - 1] != 'b')
buf[i++] = 'b';
buf[i] = '\0';
/* Check that the mode is valid. */
if (strcmp (buf, "rb") == 0)
readp = 1;
else if (strcmp (buf, "wb") == 0)
writep = 1;
else if (strcmp (buf, "ab") == 0)
writep = 1;
else if (strcmp (buf, "r+b") == 0)
readp = writep = 1;
else if (strcmp (buf, "w+b") == 0)
readp = writep = 1;
else if (strcmp (buf, "a+b") == 0)
readp = writep = 1;
else
{
sprintf (vm->error, "File.%s(): illegal open mode \"%s\"",
js_vm_symname (vm, method), buf);
js_vm_error (vm);
}
if (ictx->stream == NULL)
{
/* Do open. */
JS_VM_ALLOCATE_FD (vm, "File.open()");
ictx->stream = js_iostream_file (fopen (ictx->path, buf), readp,
writep, 1);
if (ictx->stream == NULL)
JS_VM_FREE_FD (vm);
else
result_return->u.vboolean = 1;
}
}
/* ***************************************************************** */
else if (method == ctx->s_close)
{
if (ictx->stream != NULL)
{
int result = 0;
if (!ictx->dont_close)
{
result = js_iostream_close (ictx->stream);
JS_VM_FREE_FD (vm);
}
ictx->stream = NULL;
result_return->u.vboolean = result >= 0;
}
}
/* ***************************************************************** */
else if (method == ctx->s_setPosition)
{
if (args->u.vinteger == 1)
{
if (args[1].type != JS_INTEGER)
goto argument_type_error;
li = args[1].u.vinteger;
i = SEEK_SET;
}
else if (args->u.vinteger == 2)
{
if (args[2].type == JS_INTEGER)
{
switch (args[2].u.vinteger)
{
case 1:
i = SEEK_CUR;
break;
case 2:
i = SEEK_END;
break;
default:
i = SEEK_SET;
break;
}
}
else
i = SEEK_SET;
}
else
goto argument_error;
if (ictx->stream && js_iostream_seek (ictx->stream, li, i) >= 0)
result_return->u.vboolean = 1;
}
/* ***************************************************************** */
else if (method == ctx->s_getPosition)
{
if (args->u.vinteger != 0)
goto argument_error;
result_return->type = JS_INTEGER;
if (ictx->stream == NULL)
result_return->u.vinteger = -1;
else
result_return->u.vinteger
= js_iostream_get_position (ictx->stream);
}
/* ***************************************************************** */
else if (method == ctx->s_eof)
{
if (args->u.vinteger != 0)
goto argument_error;
if (ictx->stream != NULL)
result_return->u.vboolean = ictx->stream->at_eof;
}
/* ***************************************************************** */
else if (method == ctx->s_read)
{
size_t got;
char *buffer;
if (args->u.vinteger != 1)
goto argument_error;
if (args[1].type != JS_INTEGER || args[1].u.vinteger < 0)
goto argument_type_error;
if (ictx->stream != NULL)
{
buffer = js_vm_alloc (vm, args[1].u.vinteger + 1);
got = js_iostream_read (ictx->stream, buffer,
args[1].u.vinteger);
if (got < 0)
got = 0;
js_vm_make_static_string (vm, result_return, buffer, got);
result_return->u.vstring->staticp = 0;
}
}
/* ***************************************************************** */
else if (method == ctx->s_readln)
{
int ch;
unsigned int bufpos = 0;
unsigned int buflen = 0;
char *buffer = NULL;
if (args->u.vinteger != 0)
goto argument_error;
if (ictx->stream != NULL)
{
/* Flush all buffered output data. */
js_iostream_flush (ictx->stream);
while (1)
{
/* Process all the data we have in the buffer. */
for (; ictx->stream->bufpos < ictx->stream->data_in_buf
&& (ictx->stream->buffer[ictx->stream->bufpos]
!= '\n');
ictx->stream->bufpos++)
{
if (bufpos >= buflen)
{
buflen += 1024;
buffer = js_vm_realloc (vm, buffer, buflen);
}
buffer[bufpos++]
= ictx->stream->buffer[ictx->stream->bufpos];
}
if (ictx->stream->bufpos >= ictx->stream->data_in_buf)
{
int result;
/* Read past the buffer. */
if (ictx->stream->at_eof)
/* EOF seen. */
break;
/* Read more data. */
js_iostream_fill_buffer (ictx->stream);
}
else
{
/* Got it. Skip the newline character. */
ictx->stream->bufpos++;
break;
}
}
/* Remove '\r' characters. */
while (bufpos > 0)
if (buffer[bufpos - 1] == '\r')
bufpos--;
else
break;
if (buffer == NULL)
/* An empty string. Allocate one byte. */
buffer = js_vm_alloc (vm, 1);
/*
* Use the data we already had. In maximum, it has only
* 1023 bytes overhead.
*/
js_vm_make_static_string (vm, result_return, buffer, bufpos);
result_return->u.vstring->staticp = 0;
}
}
/* ***************************************************************** */
else if (method == ctx->s_readByte)
{
result_return->type = JS_INTEGER;
if (ictx->stream == NULL)
result_return->u.vinteger = -1;
else
{
retry:
if (ictx->stream->bufpos < ictx->stream->data_in_buf)
result_return->u.vinteger
= ictx->stream->buffer[ictx->stream->bufpos++];
else
{
if (ictx->stream->at_eof)
result_return->u.vinteger = -1;
else
{
js_iostream_fill_buffer (ictx->stream);
goto retry;
}
}
}
}
/* ***************************************************************** */
else if (method == ctx->s_write || method == ctx->s_writeln)
{
size_t wrote;
int autoflush;
if (args->u.vinteger != 1)
goto argument_error;
if (args[1].type != JS_STRING)
goto argument_type_error;
if (ictx->stream != NULL)
{
autoflush = ictx->stream->autoflush;
ictx->stream->autoflush = 0;
wrote = js_iostream_write (ictx->stream,
args[1].u.vstring->data,
args[1].u.vstring->len);
if (wrote == args[1].u.vstring->len)
{
/* Success. */
result_return->u.vboolean = 1;
if (method == ctx->s_writeln)
if (js_iostream_write (ictx->stream,
JS_HOST_LINE_BREAK,
JS_HOST_LINE_BREAK_LEN) < 0)
/* No, it was not a success. */
result_return->u.vboolean = 0;
}
ictx->stream->autoflush = autoflush;
if (autoflush)
js_iostream_flush (ictx->stream);
}
}
/* ***************************************************************** */
else if (method == ctx->s_writeByte)
{
unsigned char buf[1];
if (args->u.vinteger != 1)
goto argument_error;
if (args[1].type != JS_INTEGER)
goto argument_type_error;
buf[0] = args[1].u.vinteger;
if (ictx->stream != NULL)
result_return->u.vboolean
= js_iostream_write (ictx->stream, buf, 1) >= 0;
}
/* ***************************************************************** */
else if (method == ctx->s_ungetByte)
{
if (args->u.vinteger != 1)
goto argument_error;
if (args[1].type != JS_INTEGER)
goto argument_type_error;
if (ictx->stream != NULL)
result_return->u.vboolean
= js_iostream_unget (ictx->stream, args[1].u.vinteger);
}
/* ***************************************************************** */
else if (method == ctx->s_flush)
{
if (args->u.vinteger != 0)
goto argument_error;
if (ictx->stream != NULL && js_iostream_flush (ictx->stream) >= 0)
result_return->u.vboolean = 1;
}
/* ***************************************************************** */
else if (method == ctx->s_getLength)
{
if (args->u.vinteger != 0)
goto argument_error;
/* The default error code is an integer -1. */
result_return->type = JS_INTEGER;
result_return->u.vinteger = -1;
if (ictx->stream != NULL)
result_return->u.vinteger
= js_iostream_get_length (ictx->stream);
}
/* ***************************************************************** */
else if (method == ctx->s_exists)
{
if (args->u.vinteger != 0)
goto argument_error;
if (ictx->stream)
{
/* Since we have opened the file, it must exist. */
result_return->u.vboolean = 1;
}
else
{
struct stat stat_st;
if (stat (ictx->path, &stat_st) >= 0)
result_return->u.vboolean = 1;
}
}
/* ***************************************************************** */
else if (method == ctx->s_error)
{
if (args->u.vinteger != 0)
goto argument_error;
result_return->type = JS_INTEGER;
if (ictx->stream == NULL)
result_return->u.vinteger = -1;
else
result_return->u.vinteger = ictx->stream->error;
}
/* ***************************************************************** */
else if (method == ctx->s_clearError)
{
if (args->u.vinteger != 0)
goto argument_error;
if (ictx->stream != NULL)
{
ictx->stream->error = 0;
result_return->u.vboolean = 1;
}
}
/* ***************************************************************** */
else
return JS_PROPERTY_UNKNOWN;
}
else
return JS_PROPERTY_UNKNOWN;
return JS_PROPERTY_FOUND;
/*
* Error handling.
*/
argument_error:
sprintf (vm->error, "File.%s(): illegal amount of arguments",
js_vm_symname (vm, method));
js_vm_error (vm);
argument_type_error:
sprintf (vm->error, "File.%s(): illegal argument",
js_vm_symname (vm, method));
js_vm_error (vm);
insecure_feature:
sprintf (vm->error, "File.%s(): not allowed in secure mode",
js_vm_symname (vm, method));
js_vm_error (vm);
/* NOTREACHED */
return 0;
}
/* Property proc. */
static int
property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info,
void *instance_context, JSSymbol property, int set, JSNode *node)
{
FileCtx *ctx = builtin_info->obj_context;
FileInstanceCtx *ictx = instance_context;
if (ictx)
{
/* Instance properties. */
if (property == ctx->s_autoFlush)
{
if (ictx->stream == NULL)
goto not_open;
if (set)
{
if (node->type != JS_BOOLEAN)
goto argument_type_error;
ictx->stream->autoflush = node->u.vboolean;
}
else
{
node->type = JS_BOOLEAN;
node->u.vboolean = ictx->stream->autoflush;
}
}
/* ***************************************************************** */
else if (property == ctx->s_bufferSize)
{
if (ictx->stream == NULL)
goto not_open;
if (set)
{
unsigned char *buf;
unsigned int len;
if (node->type != JS_INTEGER)
goto argument_type_error;
js_iostream_flush (ictx->stream);
len = node->u.vinteger;
buf = js_realloc (vm, ictx->stream->buffer, len);
ictx->stream->buflen = len;
ictx->stream->buffer = buf;
}
else
{
node->type = JS_INTEGER;
node->u.vinteger = ictx->stream->buflen;
}
}
/* ***************************************************************** */
else
{
if (!set)
node->type = JS_UNDEFINED;
return JS_PROPERTY_UNKNOWN;
}
}
else
{
if (!set)
node->type = JS_UNDEFINED;
return JS_PROPERTY_UNKNOWN;
}
return JS_PROPERTY_FOUND;
/* Error handling. */
argument_type_error:
sprintf (vm->error, "File.%s: illegal value",
js_vm_symname (vm, property));
js_vm_error (vm);
not_open:
sprintf (vm->error, "File.%s: the stream is not opened",
js_vm_symname (vm, property));
js_vm_error (vm);
/* NOTREACHED */
return 0;
}
/* New proc. */
static void
new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, JSNode *args,
JSNode *result_return)
{
FileInstanceCtx *instance;
if (args->u.vinteger != 1)
{
sprintf (vm->error, "new File(): illegal amount of arguments");
js_vm_error (vm);
}
if (args[1].type != JS_STRING)
{
sprintf (vm->error, "new File(): illegal argument");
js_vm_error (vm);
}
instance = js_calloc (vm, 1, sizeof (*instance));
instance->path = js_string_to_c_string (vm, &args[1]);
instance->vm = vm;
js_vm_builtin_create (vm, result_return, builtin_info, instance);
}
/* Delete proc. */
static void
delete_proc (JSBuiltinInfo *builtin_info, void *instance_context)
{
FileInstanceCtx *ictx = instance_context;
if (ictx)
{
if (ictx->stream)
{
if (!ictx->dont_close)
{
js_iostream_close (ictx->stream);
JS_VM_FREE_FD (ictx->vm);
}
ictx->stream = NULL;
}
js_free (ictx->path);
js_free (ictx);
}
}
/*
* Global functions.
*/
void
js_builtin_File (JSVirtualMachine *vm)
{
JSNode *n;
JSBuiltinInfo *info;
FileCtx *ctx;
ctx = js_calloc (vm, 1, sizeof (*ctx));
ctx->s_byteToString = js_vm_intern (vm, "byteToString");
ctx->s_chmod = js_vm_intern (vm, "chmod");
ctx->s_lstat = js_vm_intern (vm, "lstat");
ctx->s_remove = js_vm_intern (vm, "remove");
ctx->s_rename = js_vm_intern (vm, "rename");
ctx->s_stat = js_vm_intern (vm, "stat");
ctx->s_stringToByte = js_vm_intern (vm, "stringToByte");
ctx->s_open = js_vm_intern (vm, "open");
ctx->s_close = js_vm_intern (vm, "close");
ctx->s_setPosition = js_vm_intern (vm, "setPosition");
ctx->s_getPosition = js_vm_intern (vm, "getPosition");
ctx->s_eof = js_vm_intern (vm, "eof");
ctx->s_read = js_vm_intern (vm, "read");
ctx->s_readln = js_vm_intern (vm, "readln");
ctx->s_readByte = js_vm_intern (vm, "readByte");
ctx->s_write = js_vm_intern (vm, "write");
ctx->s_writeln = js_vm_intern (vm, "writeln");
ctx->s_writeByte = js_vm_intern (vm, "writeByte");
ctx->s_ungetByte = js_vm_intern (vm, "ungetByte");
ctx->s_flush = js_vm_intern (vm, "flush");
ctx->s_getLength = js_vm_intern (vm, "getLength");
ctx->s_exists = js_vm_intern (vm, "exists");
ctx->s_error = js_vm_intern (vm, "error");
ctx->s_clearError = js_vm_intern (vm, "clearError");
ctx->s_autoFlush = js_vm_intern (vm, "autoFlush");
ctx->s_bufferSize = js_vm_intern (vm, "bufferSize");
/* Object information. */
info = js_vm_builtin_info_create (vm);
info->method_proc = method;
info->property_proc = property;
info->new_proc = new_proc;
info->delete_proc = delete_proc;
info->obj_context = ctx;
info->obj_context_delete = js_free;
/* Define it. */
n = &vm->globals[js_vm_intern (vm, "File")];
js_vm_builtin_create (vm, n, info, NULL);
}
void
js_builtin_File_new (JSVirtualMachine *vm, JSNode *result_return,
char *path, JSIOStream *stream, int dont_close)
{
JSNode *n;
FileInstanceCtx *ictx;
/* Lookup our context. */
n = &vm->globals[js_vm_intern (vm, "File")];
/* Create a file instance. */
ictx = js_calloc (vm, 1, sizeof (*ictx));
ictx->path = js_strdup (vm, path);
ictx->stream = stream;
ictx->dont_close = dont_close;
ictx->vm = vm;
/* Create the builtin. */
js_vm_builtin_create (vm, result_return, n->u.vbuiltin->info, ictx);
}
#endif /*CL_EXPERIMENTAL*/