Skip to content

Commit 6117c26

Browse files
committed
Add type checking for all JS library decorators
See #20107
1 parent 9c0efe9 commit 6117c26

File tree

4 files changed

+55
-15
lines changed

4 files changed

+55
-15
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ See docs/process.md for more on how version tagging works.
2121
3.1.46 (in development)
2222
-----------------------
2323
- libunwind updated to LLVM 16.0.6. (#20088)
24+
- JS library decorators such as `__deps` and `__async` are now type checked so
25+
that errors are not silently ignored.
2426

2527
3.1.45 - 08/23/23
2628
-----------------

src/library_syscall.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ var SyscallsLibrary = {
838838
return ___syscall_statfs64(0, size, buf);
839839
},
840840
__syscall_fadvise64__nothrow: true,
841-
__syscall_fadvise64__proxy: false,
841+
__syscall_fadvise64__proxy: 'none',
842842
__syscall_fadvise64: (fd, offset, len, advice) => {
843843
return 0; // your advice is important to us (but we can't use it)
844844
},

src/utility.js

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,50 @@ function mergeInto(obj, other, options = null) {
145145
}
146146

147147
for (const key of Object.keys(other)) {
148-
if (key.endsWith('__sig')) {
149-
if (obj.hasOwnProperty(key)) {
150-
const oldsig = obj[key];
151-
const newsig = other[key];
152-
if (oldsig == newsig) {
153-
warn(`signature redefinition for: ${key}`);
154-
} else {
155-
error(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`);
148+
if (isDecorator(key)) {
149+
if (key.endsWith('__sig')) {
150+
if (obj.hasOwnProperty(key)) {
151+
const oldsig = obj[key];
152+
const newsig = other[key];
153+
if (oldsig == newsig) {
154+
warn(`signature redefinition for: ${key}`);
155+
} else {
156+
error(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`);
157+
}
156158
}
157159
}
158-
}
159160

160-
if (key.endsWith('__deps')) {
161-
const deps = other[key];
162-
if (!Array.isArray(deps)) {
163-
error(`JS library directive ${key}=${deps.toString()} is of type ${typeof deps}, but it should be an array`);
161+
const index = key.lastIndexOf('__');
162+
const decoratorName = key.slice(index);
163+
const type = typeof other[key];
164+
165+
// Specific type checking for `__deps` which is expected to be an array
166+
// (not just any old `object`)
167+
if (decoratorName === '__deps') {
168+
const deps = other[key];
169+
if (!Array.isArray(deps)) {
170+
error(`JS library directive ${key}=${deps.toString()} is of type '${type}', but it should be an array`);
171+
}
172+
} else {
173+
// General type checking for all other decorators
174+
const decoratorTypes = {
175+
'__sig': 'string',
176+
'__proxy': 'string',
177+
'__asm': 'boolean',
178+
'__inline': 'boolean',
179+
'__postset': ['string', 'function'],
180+
'__docs': 'string',
181+
'__nothrow': 'boolean',
182+
'__noleakcheck': 'boolean',
183+
'__internal': 'boolean',
184+
'__user': 'boolean',
185+
'__async': 'boolean',
186+
'__i53abi': 'boolean',
187+
}
188+
const expected = decoratorTypes[decoratorName];
189+
if (type !== expected && !expected.includes(type)) {
190+
error(`Dectorator (${key}} has wrong type. Expected '${expected}' not '${type}'`);
191+
}
164192
}
165193
}
166194
}

test/test_other.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3966,7 +3966,17 @@ def test_js_lib_invalid_deps(self):
39663966
}
39673967
''')
39683968
err = self.expect_fail([EMCC, 'src.c', '--js-library', 'lib.js'])
3969-
self.assertContained('lib.js: JS library directive jslibfunc__deps=hello is of type string, but it should be an array', err)
3969+
self.assertContained('lib.js: JS library directive jslibfunc__deps=hello is of type \'string\', but it should be an array', err)
3970+
3971+
def test_js_lib_invalid_decorator(self):
3972+
create_file('lib.js', r'''
3973+
addToLibrary({
3974+
jslibfunc__async: 'hello',
3975+
jslibfunc: (x) => {},
3976+
});
3977+
''')
3978+
err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'])
3979+
self.assertContained("lib.js: Dectorator (jslibfunc__async} has wrong type. Expected 'boolean' not 'string'", err)
39703980

39713981
def test_js_lib_legacy(self):
39723982
create_file('lib.js', r'''

0 commit comments

Comments
 (0)