duktape icon indicating copy to clipboard operation
duktape copied to clipboard

%%n used in a non-immutable format string: %s

Open PaTiToMaSteR opened this issue 3 years ago • 6 comments

I'm trying to use a bundle.js generated with webpack trying to export ethers.js

import { ethers } from 'ethers';
exports.ETH = ethers;

Doesn't matter how complex is the bundle.js I always get the same error (image and bundle.js attached Screen Shot 2022-01-14 at 22 16 15 bundle.js.zip )

Any help is highly appreciated!

PaTiToMaSteR avatar Jan 14 '22 21:01 PaTiToMaSteR

I even tried with this one as a bundle.js

(function(){"use strict";var __webpack_modules__={686:function(){eval('\n;// CONCATENATED MODULE: external "ethers"\nvar external_ethers_namespaceObject = require("ethers");\n;// CONCATENATED MODULE: ./src/index.js\n\nexports.ETH = external_ethers_namespaceObject.ethers;//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNjg2LmpzIiwibWFwcGluZ3MiOiI7O0FBQUEsSUFBSSwrQkFBNEIscUI7O0FDQWhDO0FBRUFDLE9BQU8sQ0FBQ0MsR0FBUixHQUFjRixzQ0FBZCIsInNvdXJjZXMiOlsid2VicGFjazovL0BtZXRhbWFzay90ZXN0LWRhcHAvZXh0ZXJuYWwgY29tbW9uanMgXCJldGhlcnNcIj8wZTUyIiwid2VicGFjazovL0BtZXRhbWFzay90ZXN0LWRhcHAvLi9zcmMvaW5kZXguanM/YjYzNSJdLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgX19XRUJQQUNLX05BTUVTUEFDRV9PQkpFQ1RfXyA9IHJlcXVpcmUoXCJldGhlcnNcIik7IiwiaW1wb3J0IHsgZXRoZXJzIH0gZnJvbSAnZXRoZXJzJztcblxuZXhwb3J0cy5FVEggPSBldGhlcnM7Il0sIm5hbWVzIjpbImV0aGVycyIsImV4cG9ydHMiLCJFVEgiXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///686\n')}},__webpack_exports__={};__webpack_modules__[686]()})();

Any webpack config recommended for this purpose?

PaTiToMaSteR avatar Jan 14 '22 21:01 PaTiToMaSteR

Could you provide some more details, e.g.:

  • Where does the error %%n used in a non-immutable format string: %s come from? Duktape API, a module loader, or some webpack generated code?
  • From the callstack I see cb_load_module() is called. What module loader is this? Could you show what that function is doing?

What looks suspicious to me is that duk_push_sprintf() is given the module source as a format string. Why would that need formatting? It's hard to say without seeing the loader code, but maybe instead of pushing the source with duk_push_string() it's accidentally using duk_push_sprintf() instead?

svaarala avatar Jan 15 '22 23:01 svaarala

I tried to encode it in UTF8 before import, however might be the issue, apologies to not paste the code, here it is @svaarala (attach the whole Xcode project):


#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "duktape.h"
#include "duk_module_node.h"

static void push_file_as_string(duk_context *ctx, const char *filename) {
	FILE *f;
	size_t len;
	char buf[16384];

	f = fopen(filename, "rb");
	if (f) {
		len = fread((void *) buf, 1, sizeof(buf), f);
		fclose(f);
		duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
	} else {
		duk_push_undefined(ctx);
	}
}

static duk_ret_t cb_resolve_module(duk_context *ctx) {
	const char *module_id;
	const char *parent_id;

	module_id = duk_require_string(ctx, 0);
	parent_id = duk_require_string(ctx, 1);

	duk_push_sprintf(ctx, "%s.js", module_id);
	printf("resolve_cb: id:'%s', parent-id:'%s', resolve-to:'%s'\n",
		module_id, parent_id, duk_get_string(ctx, -1));

	return 1;
}

static char* readFile(const char *filename)
{
	FILE *f = fopen(filename, "rt");
	assert(f);
	fseek(f, 0, SEEK_END);
	long length = ftell(f);
	fseek(f, 0, SEEK_SET);
	char *buffer = (char *) malloc(length + 1);
	buffer[length] = '\0';
	fread(buffer, 1, length, f);
	fclose(f);
	return buffer;
}

static void cleanUpContent(char* buffer)
{
	for(int i = 0; ; ++i) {
	  if(buffer[i] == '\n') {
		  buffer[i] = ' ';
		break;
	  }
	}
	/*
	long len = strlen(buffer);
	
	for(int i = 0; i < len; ++i)
	{
		if(buffer[i] == '\n')
		{
			buffer[i] = ' ';
		}
	}
	*/
}

static duk_ret_t cb_load_module(duk_context *ctx) {
	const char *filename;
	const char *module_id;

	module_id = duk_require_string(ctx, 0);
	duk_get_prop_string(ctx, 2, "filename");
	filename = duk_require_string(ctx, -1);
	//
	// File to memory (without checking the size)
	//
	char* content = readFile(filename);
	
	if (content)
	{
		//cleanUpContent(content);
		//printf("%s", content);
		duk_push_sprintf(ctx, content, module_id);
	}
	else
	{
		printf("load_cb: id:'%s', filename:'%s'\n", module_id, filename);

		if (strcmp(module_id, "pig.js") == 0) {
			duk_push_sprintf(ctx, "module.exports = 'you\\'re about to get eaten by %s';",
				module_id);
		} else if (strcmp(module_id, "cow.js") == 0) {
			duk_push_string(ctx, "module.exports = require('pig');");
		} else if (strcmp(module_id, "ape.js") == 0) {
			duk_push_string(ctx, "module.exports = { module: module, __filename: __filename, wasLoaded: module.loaded };");
		} else if (strcmp(module_id, "badger.js") == 0) {
			duk_push_string(ctx, "exports.foo = 123; exports.bar = 234;");
		} else if (strcmp(module_id, "comment.js") == 0) {
			duk_push_string(ctx, "exports.foo = 123; exports.bar = 234; // comment");
		} else if (strcmp(module_id, "shebang.js") == 0) {
			duk_push_string(ctx, "#!ignored\nexports.foo = 123; exports.bar = 234;");
		} else {
			(void) duk_type_error(ctx, "cannot find module: %s", module_id);
		}

	}
	
	return 1;
}

static duk_ret_t handle_print(duk_context *ctx) {
	printf("%s\n", duk_safe_to_string(ctx, 0));
	return 0;
}

static duk_ret_t handle_assert(duk_context *ctx) {
	if (duk_to_boolean(ctx, 0)) {
		return 0;
	}
	(void) duk_generic_error(ctx, "assertion failed: %s", duk_safe_to_string(ctx, 1));
	return 0;
}

int main(int argc, char *argv[]) {
	duk_context *ctx;
	int i;
	int exitcode = 0;

	ctx = duk_create_heap_default();
	if (!ctx) {
		return 1;
	}

	duk_push_c_function(ctx, handle_print, 1);
	duk_put_global_string(ctx, "print");
	duk_push_c_function(ctx, handle_assert, 2);
	duk_put_global_string(ctx, "assert");

	duk_push_object(ctx);
	duk_push_c_function(ctx, cb_resolve_module, DUK_VARARGS);
	duk_put_prop_string(ctx, -2, "resolve");
	duk_push_c_function(ctx, cb_load_module, DUK_VARARGS);
	duk_put_prop_string(ctx, -2, "load");
	duk_module_node_init(ctx);
	printf("top after init: %ld\n", (long) duk_get_top(ctx));

	for (i = 1; i < argc; i++) {
		printf("Evaling: %s\n", argv[i]);
		if (duk_peval_string(ctx, argv[i]) != 0) {
			if (duk_get_prop_string(ctx, -1, "stack")) {
				duk_replace(ctx, -2);
			} else {
				duk_pop(ctx);
			}
			exitcode = 1;
		}
		printf("--> %s\n", duk_safe_to_string(ctx, -1));
		duk_pop(ctx);
	}

	printf("Done\n");
	duk_destroy_heap(ctx);
	return exitcode;
}
Screen Shot 2022-01-16 at 07 37 06 [module-node.zip](https://github.com/svaarala/duktape/files/7876501/module-node.zip)

PaTiToMaSteR avatar Jan 16 '22 06:01 PaTiToMaSteR

yeah you totally right: duk_push_string I was using duk_push_sprintf stupidly. Now I have other errors but seems to be maybe the formatting of the ES5?

resolve_cb: id:'bundle', parent-id:'', resolve-to:'bundle.js'
--> SyntaxError: parse error (line 447)
    at [anon] (input:447) internal
    at [anon] (/Users/alvaro.martin/Downloads/duktape-2.6.0/extras/module-node/module-node/module-node/prep/duktape.c:71529) internal
    at eval () native strict directeval preventsyield
    at [anon] (bundle.js:1) strict
    at n (bundle.js:1) strict
    at [anon] (bundle.js:1) strict
    at main (bundle.js:1) strict preventsyield
    at require () native strict preventsyield
    at eval (eval:1) preventsyield
Done

Same error trying this format:

'use strict';

(function () {
  var __webpack_modules__ = { 526: function _() {
      eval('print("ethers.version");//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9AbWV0YW1hc2svdGVzdC1kYXBwLy4vc3JjL2luZGV4LmpzP2I2MzUiXSwibmFtZXMiOlsicHJpbnQiXSwibWFwcGluZ3MiOiJBQUNBQSxLQUFLLENBQUMsZ0JBQUQsQ0FBTCIsInNvdXJjZXNDb250ZW50IjpbIlxucHJpbnQoXCJldGhlcnMudmVyc2lvblwiKTsiXSwiZmlsZSI6IjUyNi5qcyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///526\n');
    } },
      __webpack_exports__ = {};__webpack_modules__[526]();
})();

With no knowledge in the source I cannot interpret what can be happening :S

PaTiToMaSteR avatar Jan 16 '22 06:01 PaTiToMaSteR

Maybe to be able to load bundles I need to implement all the calls, like "eval"?

PaTiToMaSteR avatar Jan 16 '22 06:01 PaTiToMaSteR

As Duktape doesn't implement all ES2015+ features it might just be that your transpilation target is too high?

svaarala avatar Jan 16 '22 22:01 svaarala