1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-21 00:25:37 +00:00

Bug 951: Lock the cache entry while the hook runs.

This commit is contained in:
Kalle Olavi Niemitalo 2008-07-08 15:13:45 +03:00 committed by Kalle Olavi Niemitalo
parent 314a41588c
commit 06c39a8ac4
5 changed files with 41 additions and 1 deletions

View File

@ -45,6 +45,8 @@ elinks.load_uri(uri, callback)
displays a fortune.
The cache object will not expire until after the callback returns.
Properties
----------
@ -183,6 +185,8 @@ elinks.preformat_html(cached, vs)
to elinks.preformat_html_hooks rather than to assign it to
elinks.preformat_html.
The cache object will not expire until after this function returns.
elinks.goto_url_hook(url)
@ -210,7 +214,14 @@ cache
The cache object mentioned in the descriptions of elinks.load_uri and
elinks.preformat_html is a wrapper for the internal ELinks cache object.
Its properties are:
ELinks passes the ECMAScript cache object as an argument to your
ECMAScript function, and keeps the corresponding document in the
cache until the function returns. After that, ELinks may remove the
document from the cache, even if the function has saved the cache
object to some global variable. Such an expired cache object does
not work but it does not crash ELinks either.
The properties of the cache object are:
cached.content (string)

View File

@ -249,6 +249,9 @@ Description:
add_fragment(cached, 0, new_string, new_len);
normalize_cache_entry(cached, new_len);
The caller must ensure that there is a reference to cached, so that
calling garbage_collection() from the event handler cannot free it.
-------------------------------------------------------------------------------
Name: quit
Managed By: The scripting subsystem/backends

View File

@ -220,6 +220,12 @@ static const JSClass cache_entry_class = {
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, cache_entry_finalize
};
/** Return an SMJS object through which scripts can access @a cached.
* If there already is such an object, return that; otherwise create a
* new one. The SMJS object holds only a weak reference to @a cached;
* so if the caller wants to guarantee that @a cached exists at least
* until a script returns, it should use lock_object() and
* unlock_object(). */
JSObject *
smjs_get_cache_entry_object(struct cache_entry *cached)
{

View File

@ -32,6 +32,13 @@ smjs_loading_callback(struct download *download, void *data)
if (!download->cached) goto end;
/* download->cached->object.refcount is typically 0 here
* because no struct document uses the cache entry. Because
* the connection is no longer using the cache entry either,
* it can be garbage collected. Don't let that happen while
* the script is using it. */
object_lock(download->cached);
assert(hop->callback);
smjs_ses = hop->ses;
@ -44,6 +51,8 @@ smjs_loading_callback(struct download *download, void *data)
JS_CallFunction(smjs_ctx, NULL, hop->callback, 1, args, &rval);
end:
if (download->cached)
object_unlock(download->cached);
mem_free(download->data);
mem_free(download);

View File

@ -513,6 +513,17 @@ maybe_pre_format_html(struct cache_entry *cached, struct session *ses)
if (!cached || cached->preformatted)
return;
/* The script called from here may indirectly call
* garbage_collection(). If the refcount of the cache entry
* were 0, it could then be freed, and the
* cached->preformatted assignment at the end of this function
* would crash. Normally, the document has a reference to the
* cache entry, and that suffices. If the following assertion
* ever fails, object_lock(cached) and object_unlock(cached)
* must be added to this function. */
assert(cached->object.refcount > 0);
if_assert_failed return;
fragment = get_cache_fragment(cached);
if (!fragment) return;