Skip to content

Commit b37f433

Browse files
committed
prevent infinite loop
1 parent 1b454ba commit b37f433

File tree

4 files changed

+154
-1
lines changed

4 files changed

+154
-1
lines changed

src/compiler/compile/Component.ts

+49-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import Slot from './nodes/Slot';
2727
import { Node, ImportDeclaration, Identifier, Program, ExpressionStatement, AssignmentExpression, Literal } from 'estree';
2828
import add_to_set from './utils/add_to_set';
2929
import check_graph_for_cycles from './utils/check_graph_for_cycles';
30-
import { print, x } from 'code-red';
30+
import { print, x, b } from 'code-red';
3131

3232
interface ComponentOptions {
3333
namespace?: string;
@@ -722,6 +722,8 @@ export default class Component {
722722
toRemove.unshift([parent, prop, index]);
723723
};
724724

725+
const toInsert = new Map();
726+
725727
walk(content, {
726728
enter(node, parent, prop, index) {
727729
if (map.has(node)) {
@@ -747,12 +749,29 @@ export default class Component {
747749
}
748750

749751
component.warn_on_undefined_store_value_references(node, parent, scope);
752+
753+
if (component.compile_options.dev) {
754+
let to_insert_for_loop_protect = component.loop_protect(node, prop, index);
755+
if (to_insert_for_loop_protect) {
756+
if (!toInsert.has(parent)) {
757+
toInsert.set(parent, []);
758+
}
759+
toInsert.get(parent).push(to_insert_for_loop_protect);
760+
}
761+
}
750762
},
751763

752764
leave(node) {
753765
if (map.has(node)) {
754766
scope = scope.parent;
755767
}
768+
if (toInsert.has(node)) {
769+
const nodes_to_insert = toInsert.get(node);
770+
for(const { index, prop, node: node_to_insert } of nodes_to_insert.reverse()) {
771+
node[prop].splice(index, 0, node_to_insert);
772+
}
773+
toInsert.delete(node);
774+
}
756775
},
757776
});
758777

@@ -836,6 +855,35 @@ export default class Component {
836855
}
837856
}
838857

858+
loop_protect(node, prop, index) {
859+
if (node.type === 'WhileStatement' ||
860+
node.type === 'ForStatement' ||
861+
node.type === 'DoWhileStatement') {
862+
const id = this.get_unique_name('LP');
863+
this.add_var({
864+
name: id.name,
865+
internal: true,
866+
});
867+
868+
const before = b`const ${id} = Date.now();`;
869+
const inside = b`
870+
if (Date.now() - ${id} > 100) {
871+
throw new Error('Infinite loop detected');
872+
}
873+
`
874+
// wrap expression statement with BlockStatement
875+
if (node.body.type !== 'BlockStatement') {
876+
node.body = {
877+
type: 'BlockStatement',
878+
body: [node.body],
879+
};
880+
}
881+
node.body.body.push(inside[0]);
882+
return { index, prop, node: before };
883+
}
884+
return null;
885+
}
886+
839887
invalidate(name, value?) {
840888
const variable = this.var_lookup.get(name);
841889

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
options: {
3+
dev: true
4+
}
5+
};
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import {
2+
SvelteComponentDev,
3+
dispatch_dev,
4+
init,
5+
noop,
6+
safe_not_equal
7+
} from "svelte/internal";
8+
9+
const file = undefined;
10+
11+
function create_fragment(ctx) {
12+
const block = {
13+
c: noop,
14+
l: function claim(nodes) {
15+
throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");
16+
},
17+
m: noop,
18+
p: noop,
19+
i: noop,
20+
o: noop,
21+
d: noop
22+
};
23+
24+
dispatch_dev("SvelteRegisterBlock", {
25+
block,
26+
id: create_fragment.name,
27+
type: "component",
28+
source: "",
29+
ctx
30+
});
31+
32+
return block;
33+
}
34+
35+
function instance($$self) {
36+
const LP = Date.now();
37+
38+
while (true) {
39+
foo();
40+
41+
if (Date.now() - LP > 100) {
42+
throw new Error("Infinite loop detected");
43+
}
44+
}
45+
46+
const LP_1 = Date.now();
47+
48+
for (; ; ) {
49+
foo();
50+
51+
if (Date.now() - LP_1 > 100) {
52+
throw new Error("Infinite loop detected");
53+
}
54+
}
55+
56+
const LP_2 = Date.now();
57+
58+
while (true) {
59+
foo();
60+
61+
if (Date.now() - LP_2 > 100) {
62+
throw new Error("Infinite loop detected");
63+
}
64+
}
65+
66+
$$self.$capture_state = () => {
67+
return {};
68+
};
69+
70+
$$self.$inject_state = $$props => {
71+
72+
};
73+
74+
return {};
75+
}
76+
77+
class Component extends SvelteComponentDev {
78+
constructor(options) {
79+
super(options);
80+
init(this, options, instance, create_fragment, safe_not_equal, {});
81+
82+
dispatch_dev("SvelteRegisterComponent", {
83+
component: this,
84+
tagName: "Component",
85+
options,
86+
id: create_fragment.name
87+
});
88+
}
89+
}
90+
91+
export default Component;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
while(true) {
3+
foo();
4+
}
5+
for(;;) {
6+
foo();
7+
}
8+
while(true) foo();
9+
</script>

0 commit comments

Comments
 (0)