-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Events and Styles String Mutation, closes #77 #122
Conversation
For most libass APIs the E.g. the following APIs do not aquire ownership over the passed
As for using |
Promise API is available in this browsers |
This changes and bug only affects struct manipulation. So the function calls remains the same.
Well, the original version do exactly that, it allocate the new string in the memory (JS Part) and set this pointer in the struct parameter. But, for some reason, it set the same address to all pointers in the struct. |
I did some debug in the WASM file to check why it overwrite all pointers, but it just allocate the address in the memory position. As it should PS: Soon I will send a PR to make it compile in debug mode with some docs |
In webOS 1.2 (WebKit ~ Chrome 27 or even 26), there is no webOS 2 has This will probably not cause an error at the parsing stage, but only at runtime. UPD:
Emscripten polyfills So the problem is the lack of |
Sorry, I thought this applied to all |
Technically, we still need this patch for IntPtr support, but if you want, we can remove then from the WebIDL file and manualy inject into a new js/cpp files ASS_Track.prototype['get_name'] = ASS_Track.prototype.get_name = /** @suppress {undefinedVars, duplicate} @this{Object} */function () {
var self = this.ptr;
return UTF8ToString(_emscripten_bind_ASS_Track_get_name_0(self));
};
ASS_Track.prototype['set_name'] = ASS_Track.prototype.set_name = /** @suppress {undefinedVars, duplicate} @this{Object} */function (arg0) {
var self = this.ptr;
ensureCache.prepare();
if (arg0 && typeof arg0 === 'object') arg0 = arg0.ptr;
else arg0 = ensureString(arg0);
_emscripten_bind_ASS_Track_set_name_1(self, arg0);
};
Object.defineProperty(ASS_Track.prototype, 'name', { get: ASS_Track.prototype.get_name, set: ASS_Track.prototype.set_name }); char* EMSCRIPTEN_KEEPALIVE emscripten_bind_ASS_Track_get_name_0(ASS_Track* self) {
return self->name;
}
void EMSCRIPTEN_KEEPALIVE emscripten_bind_ASS_Track_set_name_1(ASS_Track* self, char* arg0) {
char* copy = (char*)malloc(strlen(arg0) + 1);
strcpy(copy, arg0);
self->name = copy;
} |
any updates on this? it's the last thing that's needed for this lib to support video streaming rather than static content |
@ThaUnknown Currently its "ready", but i need to do some changes in the webidl generator and i need to do more tests. There is a test implementation here if you want to try it out |
0795461
to
48d5443
Compare
@TheOneric I recreated the webidl_binder history, from the original version in the Emscripten repository and added headers to explain the patches. |
Thanks! This already makes the patches much clearer. Regarding the 3rd “malloc/strcpy on struct string setters” patch, it would be nice if the “why doesn't this cause memleaks” could be documented in the patchfile description if we go that route or otherwise at least the commit message. |
Regarding Promise here are relevant quotes from libass' IRC-channel:
|
why not just use a callback, the user can easily promisify it and you're breaking compat anyways so it's not like that matters |
48d5443
to
93a9827
Compare
Use as base this files: https://github.com/emscripten-core/emscripten/blob/f36f9fcaf83db93e6a6d0f0cdc47ab6379ade139/third_party/WebIDL.py https://github.com/emscripten-core/emscripten/blob/c834ef7d69ccb4100239eeba0b0f6573fed063bc/tools/tempfiles.py https://github.com/emscripten-core/emscripten/blob/f36f9fcaf83db93e6a6d0f0cdc47ab6379ade139/tools/webidl_binder.py
93a9827
to
0797f31
Compare
@ThaUnknown changed to callbacks, thanks. @TheOneric I squash those commits and add the patches to the webidl_binder directory. Please check if the malloc commit text is correct and well explained. |
If someone want to do a final checkup please say now, if there is no problem i'll merge it on Saturday. |
Sorry for my late reply. Having the patch files is good and none of the commits should break the build. I would still prefer the struct string setters to be explicitly A more concise commit and patch description for the struct setter could be eg:
|
Sorry for that.
After further investigation, i get where the bug occurs, in the WebIDL generated glue code, in the ensureCache, the pointer stays the same in every setter. The prepare function, make use of the same pointer in every run. SubOctpInterface.js var ensureCache = {
buffer: 0, // the main buffer of temporary storage
size: 0, // the size of buffer
pos: 0, // the next free offset in buffer
temps: [], // extra allocations
needed: 0, // the total size we need next time
prepare: function() {
if (ensureCache.needed) {
// clear the temps
for (var i = 0; i < ensureCache.temps.length; i++) {
Module['_free'](ensureCache.temps[i]);
}
ensureCache.temps.length = 0;
// prepare to allocate a bigger buffer
Module['_free'](ensureCache.buffer);
ensureCache.buffer = 0;
ensureCache.size += ensureCache.needed;
// clean up
ensureCache.needed = 0;
}
if (!ensureCache.buffer) { // happens first time, or when we need to grow
ensureCache.size += 128; // heuristic, avoid many small grow events
ensureCache.buffer = Module['_malloc'](ensureCache.size);
assert(ensureCache.buffer);
}
ensureCache.pos = 0;
},
alloc: function(array, view) {
assert(ensureCache.buffer);
var bytes = view.BYTES_PER_ELEMENT;
var len = array.length * bytes;
len = (len + 7) & -8; // keep things aligned to 8 byte boundaries
var ret;
if (ensureCache.pos + len >= ensureCache.size) {
// we failed to allocate in the buffer, ensureCache time around :(
assert(len > 0); // null terminator, at least
ensureCache.needed += len;
ret = Module['_malloc'](len);
ensureCache.temps.push(ret);
} else {
// we can allocate in the buffer
ret = ensureCache.buffer + ensureCache.pos;
ensureCache.pos += len;
}
return ret;
},
copy: function(array, view, offset) {
offset >>>= 0;
var bytes = view.BYTES_PER_ELEMENT;
switch (bytes) {
case 2: offset >>>= 1; break;
case 4: offset >>>= 2; break;
case 8: offset >>>= 3; break;
}
for (var i = 0; i < array.length; i++) {
view[offset + i] = array[i];
}
},
}; Override the ensureCache value is easy and not require any patches to webidl_binder Setter example: ASS_Style.prototype['set_Name'] = ASS_Style.prototype.set_Name = /** @suppress {undefinedVars, duplicate} @this{Object} */function(arg0) {
var self = this.ptr;
ensureCache.prepare();
if (arg0 && typeof arg0 === 'object') arg0 = arg0.ptr;
else arg0 = ensureString(arg0);
_emscripten_bind_ASS_Style_set_Name_1(self, arg0);
}; |
Add new function fetchFromWorker with callback to allow fetch the response from worker Add callbacks to getStyles and getEvents functions
a37619b
to
bcce36d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concept good though I'm not familiar enough with WebIDL to comment on the patch details; I'm trusting in your testing and experience with WebIDL.
Just two minor nits, feel free to ignore them if you disagree: can you also add a comment for the "Owner" patch to WebIDL.py as you did in previous versions? And can you remove the src/SubtitleOctopus.idl
bits from the patchfile? Unlike the other parts those won't need to be reapplied when the WebIDL infrastructure gets updated from upstream.
Currently the ensureCache create a temporary pointer that will transfer the value to the WASM/C part and recycle it with to use in the next value, but since the libass struct pointers are owned by the library, the pointers can't be recycled or freed or can lead into an undefined behavior. This configure the binder to tranfer the pointer ownership instead of recycle it. To avoid creating complex code, I decided to fix it in the webidl binder.
Done
Done |
Closes #77
@TheOneric