Пример #1
0
static duk_ret_t test_1(duk_context *ctx) {
	duk_int_t i, j, n;
	char *ptr;

	duk_set_top(ctx, 0);
	duk_push_undefined(ctx);
	duk_push_null(ctx);
	duk_push_true(ctx);
	duk_push_false(ctx);
	duk_push_int(ctx, 1);
	duk_push_number(ctx, -123.456);
	duk_push_nan(ctx);
	duk_push_number(ctx, INFINITY);
	duk_push_number(ctx, -INFINITY);
	duk_push_string(ctx, "");
	duk_push_string(ctx, "foo");
	duk_push_lstring(ctx, "foo\0bar", 7);
	duk_push_object(ctx);
	duk_push_thread(ctx);
	(void) duk_push_fixed_buffer(ctx, 0);
	ptr = (char *) duk_push_fixed_buffer(ctx, 16);
	for (i = 0; i < 16; i++) {
		ptr[i] = (char) ('a' + i);
	}
	(void) duk_push_dynamic_buffer(ctx, 0);
	ptr = (char *) duk_push_dynamic_buffer(ctx, 16);
	for (i = 0; i < 16; i++) {
		ptr[i] = (char) ('a' + i);
	}
	duk_push_pointer(ctx, (void *) NULL);
	duk_push_pointer(ctx, (void *) 0xdeadbeef);

	n = duk_get_top(ctx);
	printf("top: %ld\n", (long) n);
	for (i = 0; i < n; i++) {
		const unsigned char *p;
		duk_size_t sz;

		duk_dup(ctx, i);
		sz = (duk_size_t) 0xdeadbeef;
		p = (const unsigned char *) duk_to_lstring(ctx, -1, &sz);
		printf("index %ld, string: '", (long) i);
		for (j = 0; j < sz; j++) {
			if (p[j] >= 0x20 && p[j] <= 0x7e) {
				printf("%c", (int) p[j]);
			} else {
				printf("\\x%02x", (int) p[j]);
			}
		}
		printf("', length %lu\n", (unsigned long) sz);
		duk_pop(ctx);

		duk_dup(ctx, i);
		sz = (duk_size_t) 0xdeadbeef;
		p = (const unsigned char *) duk_to_lstring(ctx, -1, NULL);
		printf("index %ld, string: '%s'\n", (long) i, (const char *) p);
		duk_pop(ctx);
	}

	return 0;
}
Пример #2
0
/* Raw helper to extract internal information / statistics about a value.
 * The return values are version specific and must not expose anything
 * that would lead to security issues (e.g. exposing compiled function
 * 'data' buffer might be an issue).  Currently only counts and sizes and
 * such are given so there should not be a security impact.
 */
duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
	duk_tval *tv;
	duk_heaphdr *h;
	duk_int_t i, n;

	tv = duk_get_tval(ctx, 0);
	DUK_ASSERT(tv != NULL);  /* because arg count is 1 */

	duk_push_array(ctx);  /* -> [ val arr ] */

	/* type tag (public) */
	duk_push_int(ctx, duk_get_type(ctx, 0));

	/* address */
	if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
		h = DUK_TVAL_GET_HEAPHDR(tv);
		duk_push_pointer(ctx, (void *) h);
	} else {
		goto done;
	}
	DUK_ASSERT(h != NULL);

	/* refcount */
#ifdef DUK_USE_REFERENCE_COUNTING
	duk_push_int(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
#else
	duk_push_undefined(ctx);
#endif

	/* heaphdr size and additional allocation size, followed by
	 * type specific stuff (with varying value count)
	 */
	switch (DUK_HEAPHDR_GET_TYPE(h)) {
	case DUK_HTYPE_STRING: {
		duk_hstring *h_str = (duk_hstring *) h;
		duk_push_int(ctx, (int) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
		break;
	}
	case DUK_HTYPE_OBJECT: {
		duk_hobject *h_obj = (duk_hobject *) h;
		duk_int_t hdr_size;
		if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
			hdr_size = (duk_int_t) sizeof(duk_hcompiledfunction);
		} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
			hdr_size = (duk_int_t) sizeof(duk_hnativefunction);
		} else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
			hdr_size = (duk_int_t) sizeof(duk_hthread);
		} else {
			hdr_size = (duk_int_t) sizeof(duk_hobject);
		}
		duk_push_int(ctx, (int) hdr_size);
		duk_push_int(ctx, (int) DUK_HOBJECT_E_ALLOC_SIZE(h_obj));
		duk_push_int(ctx, (int) h_obj->e_size);
		duk_push_int(ctx, (int) h_obj->e_used);
		duk_push_int(ctx, (int) h_obj->a_size);
		duk_push_int(ctx, (int) h_obj->h_size);
		if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
			duk_hbuffer *h_data = ((duk_hcompiledfunction *) h_obj)->data;
			if (h_data) {
				duk_push_int(ctx, DUK_HBUFFER_GET_SIZE(h_data));
			} else {
				duk_push_int(ctx, 0);
			}
		}
		break;
	}
	case DUK_HTYPE_BUFFER: {
		duk_hbuffer *h_buf = (duk_hbuffer *) h;
		if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
			/* XXX: when usable_size == 0, dynamic buf ptr may now be NULL, in which case
			 * the second allocation does not exist.
			 */
			duk_hbuffer_dynamic *h_dyn = (duk_hbuffer_dynamic *) h;
			duk_push_int(ctx, (int) (sizeof(duk_hbuffer_dynamic)));
			duk_push_int(ctx, (int) (DUK_HBUFFER_DYNAMIC_GET_ALLOC_SIZE(h_dyn)));
		} else {
			duk_push_int(ctx, (int) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
		}
		break;

	}
	}

 done:
	/* set values into ret array */
	/* FIXME: primitive to make array from valstack slice */
	n = duk_get_top(ctx);
	for (i = 2; i < n; i++) {
		duk_dup(ctx, i);
		duk_put_prop_index(ctx, 1, i - 2);
	}
	duk_dup(ctx, 1);
	return 1;
}
static duk_ret_t test_1(duk_context *ctx) {
	duk_idx_t i, n;

	duk_set_top(ctx, 0);

	duk_push_undefined(ctx);
	duk_push_null(ctx);
	duk_push_true(ctx);
	duk_push_false(ctx);
	duk_push_int(ctx, 0);
	duk_push_int(ctx, 1);
	duk_push_int(ctx, -1);
	duk_push_number(ctx, 123.456);
	duk_push_number(ctx, -123.456);
	duk_push_number(ctx, 123.999);

	duk_push_number(ctx, -123.999);
	duk_push_number(ctx, -2147483649.0); /* min int32 - 1 */
	duk_push_number(ctx, -2147483648.0); /* min int32 */
	duk_push_number(ctx, 2147483647.0);  /* max int32 */
	duk_push_number(ctx, 2147483648.0);  /* max int32 + 1 */
	duk_push_number(ctx, 4294967295.0);  /* max uint32 */
	duk_push_number(ctx, 4294967296.0);  /* max uint32 + 1 */
	duk_push_number(ctx, 65535.0);       /* max uint16 */
	duk_push_number(ctx, 65536.0);       /* max uint16 + 1 */
	duk_push_number(ctx, 9999999999.0);

	duk_push_nan(ctx);
	duk_push_number(ctx, INFINITY);
	duk_push_string(ctx, "");
	duk_push_string(ctx, "foo");
	duk_push_string(ctx, "123");
	duk_push_string(ctx, "123.456");
	duk_push_string(ctx, "123.456e3");
	duk_push_string(ctx, "  -123.456e+3  ");
	duk_push_string(ctx, "NaN");
	duk_push_string(ctx, "-Infinity");

	duk_push_string(ctx, "+Infinity");
	duk_push_string(ctx, "Infinity");
	duk_push_string(ctx, "Infinityx");
	duk_push_string(ctx, "xInfinity");
	duk_push_string(ctx, "  Infinity  ");
	duk_push_object(ctx);
	duk_push_thread(ctx);
	duk_push_fixed_buffer(ctx, 0);     /* ToNumber('') = 0 */
	duk_push_fixed_buffer(ctx, 1024);  /* ToNumber('\u0000...') = NaN, converts into 0 when doing integer coercion */
	duk_push_dynamic_buffer(ctx, 0);

	duk_push_dynamic_buffer(ctx, 1024);
	duk_push_pointer(ctx, (void *) NULL);
	duk_push_pointer(ctx, (void *) 0xdeadbeef);

	n = duk_get_top(ctx);
	printf("top: %ld\n", (long) n);
	for (i = 0; i < n; i++) {
		duk_double_t dval_pre;
		duk_double_t dval_post;
		duk_int_t ival;
		duk_uint_t uval;

		duk_dup(ctx, i);
		dval_pre = duk_get_number(ctx, -1);
		ival = duk_to_int32(ctx, -1);
		dval_post = duk_get_number(ctx, -1);
		printf("index %ld, int32: %ld, number before: %lf, number after: %lf\n",
		       (long) i, (long) ival, (double) dval_pre, (double) dval_post);
		duk_pop(ctx);

		duk_dup(ctx, i);
		dval_pre = duk_get_number(ctx, -1);
		uval = duk_to_uint32(ctx, -1);
		dval_post = duk_get_number(ctx, -1);
		printf("index %ld, uint32: %lu, number before: %lf, number after: %lf\n",
		       (long) i, (unsigned long) uval, (double) dval_pre, (double) dval_post);
		duk_pop(ctx);

		duk_dup(ctx, i);
		dval_pre = duk_get_number(ctx, -1);
		uval = duk_to_uint16(ctx, -1);
		dval_post = duk_get_number(ctx, -1);
		printf("index %ld, uint16: %lu, number before: %lf, number after: %lf\n",
		       (long) i, (unsigned long) uval, (double) dval_pre, (double) dval_post);
		duk_pop(ctx);
	}

	return 0;
}
Пример #4
0
/* Raw helper to extract internal information / statistics about a value.
 * The return values are version specific and must not expose anything
 * that would lead to security issues (e.g. exposing compiled function
 * 'data' buffer might be an issue).  Currently only counts and sizes and
 * such are given so there should not be a security impact.
 */
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_tval *tv;
	duk_heaphdr *h;
	duk_int_t i, n;

	DUK_UNREF(thr);

	/* result array */
	duk_push_array(ctx);  /* -> [ val arr ] */

	/* type tag (public) */
	duk_push_int(ctx, duk_get_type(ctx, 0));

	/* address */
	tv = duk_get_tval(ctx, 0);
	DUK_ASSERT(tv != NULL);  /* because arg count is 1 */
	if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
		h = DUK_TVAL_GET_HEAPHDR(tv);
		duk_push_pointer(ctx, (void *) h);
	} else {
		/* internal type tag */
		duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
		goto done;
	}
	DUK_ASSERT(h != NULL);

	/* refcount */
#ifdef DUK_USE_REFERENCE_COUNTING
	duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
#else
	duk_push_undefined(ctx);
#endif

	/* heaphdr size and additional allocation size, followed by
	 * type specific stuff (with varying value count)
	 */
	switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
	case DUK_HTYPE_STRING: {
		duk_hstring *h_str = (duk_hstring *) h;
		duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
		break;
	}
	case DUK_HTYPE_OBJECT: {
		duk_hobject *h_obj = (duk_hobject *) h;
		duk_small_uint_t hdr_size;
		if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
			hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction);
		} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
			hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction);
		} else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
			hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
		} else {
			hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
		}
		duk_push_uint(ctx, (duk_uint_t) hdr_size);
		duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_E_ALLOC_SIZE(h_obj));
		duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
		/* Note: e_next indicates the number of gc-reachable entries
		 * in the entry part, and also indicates the index where the
		 * next new property would be inserted.  It does *not* indicate
		 * the number of non-NULL keys present in the object.  That
		 * value could be counted separately but requires a pass through
		 * the key list.
		 */
		duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
		duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
		duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
		if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
			duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
			if (h_data) {
				duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data));
			} else {
				duk_push_uint(ctx, 0);
			}
		}
		break;
	}
	case DUK_HTYPE_BUFFER: {
		duk_hbuffer *h_buf = (duk_hbuffer *) h;
		if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
			if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
				duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external)));
			} else {
				/* When alloc_size == 0 the second allocation may not
				 * actually exist.
				 */
				duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic)));
			}
			duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)));
		} else {
			duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
		}
		break;

	}
	}

 done:
	/* set values into ret array */
	/* XXX: primitive to make array from valstack slice */
	n = duk_get_top(ctx);
	for (i = 2; i < n; i++) {
		duk_dup(ctx, i);
		duk_put_prop_index(ctx, 1, i - 2);
	}
	duk_dup(ctx, 1);
	return 1;
}
Пример #5
0
			/* in interactive mode, write to stdout */
			print_pop_error(ctx, stdout);
			retval = -1;  /* an error 'taints' the execution */
		} else {
			duk_pop(ctx);
		}
	}

 done:
	if (buffer) {
		free(buffer);
		buffer = NULL;
	}

	return retval;
}
#else  /* NO_READLINE */
static int handle_interactive(duk_context *ctx) {
	const char *prompt = "duk> ";
	char *buffer = NULL;
	int retval = 0;
	int rc;

	duk_eval_string(ctx, GREET_CODE(""));
	duk_pop(ctx);

	/*
	 *  Note: using readline leads to valgrind-reported leaks inside
	 *  readline itself.  Execute code from an input file (and not
	 *  through stdin) for clean valgrind runs.
	 */

	rl_initialize();

	for (;;) {
		if (buffer) {
			free(buffer);
			buffer = NULL;
		}

		buffer = readline(prompt);
		if (!buffer) {
			break;
		}

		if (buffer && buffer[0] != (char) 0) {
			add_history(buffer);
		}

		duk_push_pointer(ctx, (void *) buffer);
		duk_push_uint(ctx, (duk_uint_t) strlen(buffer));
		duk_push_string(ctx, "input");

		interactive_mode = 1;  /* global */

		rc = duk_safe_call(ctx, wrapped_compile_execute, 3 /*nargs*/, 1 /*nret*/);

#if defined(DUK_CMDLINE_AJSHEAP)
		ajsheap_clear_exec_timeout();
#endif

		if (buffer) {
			free(buffer);
			buffer = NULL;
		}

		if (rc != DUK_EXEC_SUCCESS) {
			/* in interactive mode, write to stdout */
			print_pop_error(ctx, stdout);
			retval = -1;  /* an error 'taints' the execution */
		} else {
			duk_pop(ctx);
		}
	}

	if (buffer) {
		free(buffer);
		buffer = NULL;
	}

	return retval;
}
Пример #6
0
static int handle_interactive(duk_context *ctx) {
	const char *prompt = "duk> ";
	char *buffer = NULL;
	int retval = 0;
	int rc;
	int got_eof = 0;

	duk_eval_string(ctx, GREET_CODE(" [no readline]"));
	duk_pop(ctx);

	buffer = (char *) malloc(LINEBUF_SIZE);
	if (!buffer) {
		fprintf(stderr, "failed to allocated a line buffer\n");
		fflush(stderr);
		retval = -1;
		goto done;
	}

	while (!got_eof) {
		size_t idx = 0;

		fwrite(prompt, 1, strlen(prompt), stdout);
		fflush(stdout);

		for (;;) {
			int c = fgetc(stdin);
			if (c == EOF) {
				got_eof = 1;
				break;
			} else if (c == '\n') {
				break;
			} else if (idx >= LINEBUF_SIZE) {
				fprintf(stderr, "line too long\n");
				fflush(stderr);
				retval = -1;
				goto done;
			} else {
				buffer[idx++] = (char) c;
			}
		}

		duk_push_pointer(ctx, (void *) buffer);
		duk_push_uint(ctx, (duk_uint_t) idx);
		duk_push_string(ctx, "input");

		interactive_mode = 1;  /* global */

		rc = duk_safe_call(ctx, wrapped_compile_execute, 3 /*nargs*/, 1 /*nret*/);

#if defined(DUK_CMDLINE_AJSHEAP)
		ajsheap_clear_exec_timeout();
#endif

		if (rc != DUK_EXEC_SUCCESS) {
			/* in interactive mode, write to stdout */
			print_pop_error(ctx, stdout);
			retval = -1;  /* an error 'taints' the execution */
		} else {
			duk_pop(ctx);
		}
	}

 done:
	if (buffer) {
		free(buffer);
		buffer = NULL;
	}

	return retval;
}
Пример #7
0
JavaScriptObject::JavaScriptObject(JavaTypeMap& typeMap, JNIEnv* env, duk_context* context,
                                   jstring name, jobjectArray methods)
    : m_name(JString(env, name).str())
    , m_context(context)
    , m_instance(nullptr)
    , m_nextFinalizer(nullptr) {
    CHECK_STACK(m_context);
    duk_push_global_object(m_context);
    if (!duk_get_prop_string(m_context, -1, m_name.c_str())) {
        duk_pop_2(m_context);
        throw std::invalid_argument("A global JavaScript object called " + m_name + " was not found");
    }

    m_instance = duk_get_heapptr(m_context, -1);
    if (m_instance == nullptr) {
        duk_pop_2(m_context);
        throw std::invalid_argument("JavaScript global called " + m_name + " is not an object");
    }

    // Make sure that the object has all of the methods we want.
    jmethodID getName = nullptr;
    const jsize numArgs = env->GetArrayLength(methods);
    for (jsize i = 0; i < numArgs; ++i) {
        auto method = env->GetObjectArrayElement(methods, i);
        if (getName == nullptr) {
            jclass methodClass = env->GetObjectClass(method);
            getName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;");
        }

        // Sanity check that as of right now, the object we're proxying has a function with this name.
        const JString methodName(env, static_cast<jstring>(env->CallObjectMethod(method, getName)));
        if (!duk_get_prop_string(m_context, -1, methodName)) {
            duk_pop_3(m_context);
            throw std::runtime_error("JavaScript global " + m_name + " has no method called " +
                                     methodName.str());
        } else if (!duk_is_callable(m_context, -1)) {
            duk_pop_3(m_context);
            throw std::runtime_error("JavaScript property " + m_name + "." + methodName.str() +
                                     " not callable");
        }

        try {
            // Build a call wrapper that handles marshalling the arguments and return value.
            m_methods.emplace(std::make_pair(env->FromReflectedMethod(method),
                                             buildMethodBody(typeMap, env, method, methodName.str())));
        } catch (const std::invalid_argument& e) {
            duk_pop_3(m_context);
            throw std::invalid_argument("In proxied method \"" + m_name + "." + methodName.str() +
                                        "\": " + e.what());
        }

        // Pop the method property.
        duk_pop(m_context);
    }

    // Keep track of any previously registered finalizer.
    duk_get_finalizer(m_context, -1);
    m_nextFinalizer = duk_is_c_function(m_context, -1)
                      ? duk_get_c_function(m_context, -1)
                      : nullptr;
    duk_pop(m_context);
    duk_push_c_function(m_context, JavaScriptObject::finalizer, 1);
    duk_set_finalizer(m_context, -2);

    // Add 'this' to the list of pointers attached to the proxied instance.
    // TODO: don't use an array here, just use a separate hidden property for each proxy.
    if (!duk_has_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME)) {
        duk_push_array(m_context);
    } else {
        duk_get_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME);
    }

    const duk_size_t length = duk_get_length(m_context, -1);
    duk_push_pointer(m_context, this);
    duk_put_prop_index(m_context, -2, static_cast<duk_uarridx_t>(length));
    // Add the array (back) to the instance.
    duk_put_prop_string(m_context, -2, WRAPPER_THIS_PROP_NAME);

    // Pop the global and our instance.
    duk_pop_2(m_context);
}