bun icon indicating copy to clipboard operation
bun copied to clipboard

Segmentation fault with EJS running under Mitata for benchmarking

Open robogeek opened this issue 2 years ago • 4 comments

Version

0.1.4

Platform

Linux davidpc 5.15.0-41-generic #44-Ubuntu SMP Wed Jun 22 14:20:53 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

What steps will reproduce the bug?

I have a simple benchmark running EJS that causes Bun to do a segmentation fault. The benchmark is using Mitata just as the Bun benchmarks do. Commenting out all EJS code lets the benchmark run okay. The benchmark runs correctly on Node.js. And running the same EJS code but not with Mitata it runs correctly on Bun.

import { bench, run } from "mitata";

import * as ejs from 'ejs';

let people = ['geddy', 'neil', 'alex'];

bench('literal', () => { return `${people.join(', ')}`; });

bench('ejs-join', () => {
    ejs.render('<%= people.join(", "); %>', { people: people });
});

try {
    await run();
} catch (err) { console.error(err); }

When executed -- of course you must install mitata and ejs -- I get this output:

SegmentationFault at 24


–––– bun meta ––––
Bun v0.1.4 Linux x64 #44-Ubuntu SMP Wed Jun 22 14:20:53 UTC 2022
AutoCommand: 
Elapsed: 27ms | User: 25ms | Sys: 4ms
RSS: 67.11MB | Peak: 32.12MB | Commit: 67.11MB | Faults: 0
–––– bun meta ––––

Ask for #help in https://bun.sh/discord or go to https://bun.sh/issues

Commenting out the bench invocation for ejs-join it still segfaults. Commenting out the import for EJS and it runs correctly.

$ bun render.mjs 
cpu: Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz
runtime: bun 0.1.4 (x64-linux)

benchmark      time (avg)             (min … max)       p75       p99      p995
------------------------------------------------- -----------------------------
literal     136.1 ns/iter (108.35 ns … 395.06 ns) 136.37 ns    307 ns 314.28 ns

Then, if I use this code (the same EJS invocation but no Mitata)

import * as ejs from 'ejs';

let people = ['geddy', 'neil', 'alex'];

console.log(ejs.render('<%= people.join(", "); %>', {people: people}));

Bun executes it correctly:

$ bun rendering.mjs 
geddy, neil, alex

How often does it reproduce? Is there a required condition?

Every time

What is the expected behavior?

Expected behavior is for the benchmark to run correctly

What do you see instead?

The segfaults discussed above.

Additional information

Both Mitata and EJS are the latest versions (3.1.8 for EJS)

robogeek avatar Jul 20 '22 20:07 robogeek

I'm trying several template engines to try a comparison. So far Liquid and Handlebars both execute correctly on Bun, but Nunjucks has a similar issue.

// NUNJUCKS

import nunjucks from 'nunjucks';

bench('nunjucks-join',  () => {
    const output = nunjucks.renderString('{{ people | join(", ") }}', { people: people });
    // console.log(output);
});

bench(`nunjucks-list`, () => {

    const output = nunjucks.renderString(`
    <ul id="products">
    {% for person in people %}
        <li>{{ person }}</li>
    {% endfor %}
    </ul>
    `, { people: people });
    // console.log(output);
});

This also causes a segfault which is only cured when commenting out the import for nunjucks

Running Nunjucks outside of Mitata with this code:

let people = ['geddy', 'neil', 'alex'];

import nunjucks from 'nunjucks';

const output = nunjucks.renderString('{{ people | join(", ") }}', { people: people });
console.log(output);

Gives this error:

20 |   _inheritsLoose(FileSystemLoader, _Loader);
21 | 
22 |   function FileSystemLoader(searchPaths, opts) {
23 |     var _this;
24 | 
25 |     _this = _Loader.call(this) || this;
                ^
 TypeError: _Loader.call is not a function. (In '_Loader.call(this)', '_Loader.call' is undefined)
      at new FileSystemLoader (/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/src/node-loaders.js:25:12)
      at configure (/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/index.js:41:21)
      at renderString (/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/index.js:96:6)
      at /home/david/Projects/akasharender/akashacms-perftest/adhoc/rendering.mjs:10:15

robogeek avatar Jul 20 '22 22:07 robogeek

Next up is MarkdownIT ... similar story. Running it in the context of Mitata causes a segmentation fault. Running it on its own executes correctly.

import { promises as fsp } from 'fs';
import MarkdownIt from 'markdown-it';

const mditConfig = {
    html:         true,         // Enable html tags in source
    xhtmlOut:     true,         // Use '/' to close single tags (<br />)
    breaks:       false,        // Convert '\n' in paragraphs into <br>
    // langPrefix:   'language-',  // CSS language prefix for fenced blocks
    linkify:      true,         // Autoconvert url-like texts to links
    typographer:  false,        // Enable smartypants and other sweet transforms
  
    // Highlighter function. Should return escaped html,
    // or '' if input not changed
    highlight: function (/*str, , lang*/) { return ''; }
};
const md = MarkdownIt(mditConfig);
// const doc1 = await fsp.readFile('fixtures/document.md', 'utf-8');

const doc1 = `
# Title 1

Some text [with a link](http://somewhere.com)

## Title 2

* Person 1
* Person 2
* Person 3
`;

bench('markdown-render',  () => {
    const output = md.render(doc1);
    // console.log(output);
});

The behavior is the same whether read from a file, or an inline constant.

$ bun render-bun.js

SegmentationFault at 24


–––– bun meta ––––
Bun v0.1.4 Linux x64 #44-Ubuntu SMP Wed Jun 22 14:20:53 UTC 2022
AutoCommand: 
Elapsed: 158ms | User: 114ms | Sys: 16ms
RSS: 67.11MB | Peak: 57.90MB | Commit: 67.11MB | Faults: 0
–––– bun meta ––––

And run without Mitata it executes correctly


import MarkdownIt from 'markdown-it';

const mditConfig = {
    html:         true,         // Enable html tags in source
    xhtmlOut:     true,         // Use '/' to close single tags (<br />)
    breaks:       false,        // Convert '\n' in paragraphs into <br>
    // langPrefix:   'language-',  // CSS language prefix for fenced blocks
    linkify:      true,         // Autoconvert url-like texts to links
    typographer:  false,        // Enable smartypants and other sweet transforms
  
    // Highlighter function. Should return escaped html,
    // or '' if input not changed
    highlight: function (/*str, , lang*/) { return ''; }
};
const md = MarkdownIt(mditConfig);
// const doc1 = await fsp.readFile('fixtures/document.md', 'utf-8');

const doc1 = `
# Title 1

Some text [with a link](http://somewhere.com)

## Title 2

* Person 1
* Person 2
* Person 3
`;

const output = md.render(doc1);
console.log(output);

robogeek avatar Jul 20 '22 22:07 robogeek

I'm unable to reproduce this on an M1, but I am able to reproduce this on Linux x64

Jarred-Sumner avatar Jul 20 '22 23:07 Jarred-Sumner

These failures happen with the Canary build of Bun 0.1.5

robogeek avatar Jul 22 '22 19:07 robogeek

With Bun 0.1.8 on Linux/x86 I now get this result -- no segfaults on the engines that had failed earlier -- but there's an issue with Nunjucks that I have not investigated yet.

> [email protected] render:bun
> bun render-bun.js

cpu: Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz
runtime: bun 0.1.8 (x64-linux)

benchmark                 time (avg)             (min … max)
------------------------------------------------------------
literal               138.63 ns/iter (113.11 ns … 589.08 ns)
ejs-join               24.47 µs/iter     (16.8 µs … 3.59 ms)
ejs-list               44.79 µs/iter    (31.96 µs … 2.98 ms)
handlebars-join-once    4.21 µs/iter     (2.94 µs … 2.44 ms)
handlebars-list-once     4.5 µs/iter   (3.33 µs … 772.88 µs)
liquid-join            39.59 µs/iter    (21.56 µs … 2.84 ms)
liquid-list           124.14 µs/iter    (81.42 µs … 1.62 ms)
nunjucks-join         error: _Loader.call is not a function. (In '_Loader.call(this)', '_Loader.call' is undefined)
FileSystemLoader@/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/src/node-loaders.js:31:27
configure@/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/index.js:31:52
renderString@/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/index.js:76:18
@/home/david/Projects/akasharender/akashacms-perftest/bench/render-bun.js:62:39
@/home/david/Projects/akasharender/akashacms-perftest/node_modules/mitata/src/lib.mjs:37:19
@/home/david/Projects/akasharender/akashacms-perftest/node_modules/mitata/src/cli.mjs:188:40
@[native code]
nunjucks-list         error: _Loader.call is not a function. (In '_Loader.call(this)', '_Loader.call' is undefined)
FileSystemLoader@/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/src/node-loaders.js:31:27
configure@/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/index.js:31:52
renderString@/home/david/Projects/akasharender/akashacms-perftest/node_modules/nunjucks/index.js:76:18
@/home/david/Projects/akasharender/akashacms-perftest/bench/render-bun.js:65:39
@/home/david/Projects/akasharender/akashacms-perftest/node_modules/mitata/src/lib.mjs:37:19
@/home/david/Projects/akasharender/akashacms-perftest/node_modules/mitata/src/cli.mjs:188:40
@[native code]
markdown-render        37.61 µs/iter    (21.89 µs … 5.59 ms)
cheerio                 94.1 µs/iter    (55.77 µs … 3.53 ms)

robogeek avatar Aug 12 '22 17:08 robogeek

BTW -Following is the same test running on Node.js. The primary performance difference is with Cheerio.

> [email protected] render:node
> node render-node.mjs

cpu: Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz
runtime: node v18.6.0 (x64-linux)

benchmark            time (avg)             (min … max)
-------------------------------------------------------
literal          137.42 ns/iter  (119.7 ns … 495.03 ns)
ejs-join          17.66 µs/iter   (13.9 µs … 832.51 µs)
ejs-list          30.77 µs/iter  (25.41 µs … 612.14 µs)
handlebars-join    6.19 µs/iter   (4.82 µs … 665.49 µs)
handlebars-list    6.46 µs/iter   (5.07 µs … 494.04 µs)
liquid-join       30.37 µs/iter    (16.69 µs … 4.29 ms)
liquid-list       95.18 µs/iter    (60.39 µs … 1.65 ms)
nunjucks-join      46.9 µs/iter    (25.24 µs … 3.39 ms)
nunjucks-list     91.13 µs/iter    (62.01 µs … 1.66 ms)
markdown-render   38.42 µs/iter  (27.24 µs … 807.91 µs)
cheerio          154.99 µs/iter    (87.67 µs … 5.14 ms)

robogeek avatar Aug 12 '22 17:08 robogeek

Thank you for trying again and posting results

That _Loader.call issue is interesting, either an issue with bun's node polyfills or a CommonJS transform bug - closing this since the original issue is fixed. Please open an issue for the nunjucks-list bug

Jarred-Sumner avatar Aug 12 '22 21:08 Jarred-Sumner