| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
| |
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1905414 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
| |
* memory/unix/apr_pools.c(apr_pool_initialize):
Use 1u for shifting to unsigned.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1902193 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
r1884078 fixed lifetime issues with detached threads by using unmanaged pool
destroyed by the thread itself on exit, with no binding to the parent pool.
This commit makes use of unmanaged pools for attached threads too, they needed
their own allocator anyway due to apr_thread_detach() being callable anytime
later. apr__pool_unmanage() was a hack to detach a subpool from its parent, but
if a subpool needs its own allocator for this to work correctly there is no
point in creating a subpool for threads (no memory reuse on destroy for short
living threads for instance).
Since an attached thread has its own lifetime now, apr_thread_join() must be
called to free its resources/pool, though it's no different than before when
destroying the parent pool was UB if the thread was still running (i.e. not
joined yet).
Let's acknoledge that threads want no binding with the pool passed to them at
creation time, besides the abort_fn which they can steal :)
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1897179 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
| |
compiler warning.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1891307 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
| |
allocator if node allocation fails, rather than leaking it.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1891202 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A detached thread is by definition out of control, unjoinable, unmanaged,
and it can terminate/exit after its parent pool is detroyed.
To avoid use-after-free in this case, let's use an unmanaged pool for detached
threads, either by creating an unmanaged pool from the start if the thread
is created detached, or by "unmanaging" the pool if the thread is detached
later with apr_thread_detach().
To "umanage" the pool, provide a new internal helper, apr__pool_unmanage()
which takes care of removing the pool from its parent's list.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1884078 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
| |
To avoid #ifdef'ery in relevant code and thus help readers.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883806 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883805 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
| |
[Correct commit in r1883805]
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883804 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
| |
[Reverted by r1883804]
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883803 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Don't release and re-acquire the lock in apr_pool_destroy_debug() between
pool_clear_debug() and the removal of the pool from the parent, so that
apr_pool_walk_tree() has no chance to find a pool being destroyed.
This is done like in apr_pool_clear_debug(), all the necessary locking goes
to apr_pool_destroy_debug() which then calls pool_destroy_debug() in the
critical section.
Note that pool_destroy_debug() when called from pool_clear_debug() is not
locking the parent mutex by itself anymore, thus the pool being cleared there
is not locked when its children are destroyed (just like before r1883750). This
is not an issue though because the parent mutex is supposed to protect against
concurrent access from apr_pool_walk_tree() on an ancestor, not an illegal
operation from another thread on a pool being cleared. That is always undefined
behaviour with debug and non-debug pools, though the latter might detect it
with apr_pool_check_owner(), not the pool being cleared's business anyway.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883802 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
After r1883800, the mutex of a pool in APR_POOL_DEBUG can't be NULL, so
remove useless NULL checks around locking.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883801 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Make apr_pool_clear_debug() always lock the parent mutex, regardless of
whether its own mutex is the same (inherited), otherwise the race with
apr_pool_walk_tree() is still not addressed in any case.
There is no risk of the mutex being destroyed while locked since it's been
created on an ancestor pool, and the cleanups can still use the mutex since
it's APR_THREAD_MUTEX_NESTED.
Also, in apr_pool_create_ex_debug(), create/inherit the mutex before the pool
is registered in the parent, or it can be accessed by apr_pool_walk_tree()
with the a NULL mutex and thus breaking the rules.
For unmanaged pools, even though they have no parent pool, they can still
have children that can be cleared/destroyed so the synchronization with
apr_pool_walk_tree() still applies. And since the allocator plays no role in
APR_POOL_DEBUG mode, apr_pool_create_unmanaged_ex_debug() must always create
the mutex, regardless of whether an allocator is provided.
While doing this change in apr_pool_create_unmanaged_ex_debug(), this commit
also moves the corresponding code (creating the mutex) at the same place as
it's moved in apr_pool_create_ex_debug(), to ease reading/comparing the two
functions.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883800 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
By using apr_pool_clear_debug() instead of pool_clear_debug() in
pool_destroy_debug() we gain the locking provided by the former and thus
protection from concurrent access from apr_pool_walk_tree(), which is
undefined behaviour.
While pool_destroy_debug()=>apr_pool_clear_debug()=>pool_clear_debug() calls
pool_destroy_debug() for all the children pools, this does not cause a deadlock
because apr_pool_clear_debug() locks the parent pool only (not the pool itself)
and thus pool_destroy_debug(pool->child) locks the current pool with no issue.
This fixes use-after-free like the below in httpd (with -D APR_POOL_DEBUG):
=================================================================
==2026856==ERROR: AddressSanitizer: heap-use-after-free on address 0x60600025acf0 at pc 0x7fe738f4c5be bp 0x7fe718598110 sp 0x7fe718598108
READ of size 8 at 0x60600025acf0 thread T51
#0 0x7fe738f4c5bd in apr_thread_mutex_lock locks/unix/thread_mutex.c:124
#1 0x7fe738f4e01c in apr_pool_walk_tree memory/unix/apr_pools.c:1505
#2 0x7fe738f4e066 in apr_pool_walk_tree memory/unix/apr_pools.c:1511
#3 0x7fe738f4e066 in apr_pool_walk_tree memory/unix/apr_pools.c:1511
#4 0x7fe738f4e066 in apr_pool_walk_tree memory/unix/apr_pools.c:1511
#5 0x7fe738f5027c in apr_pool_find memory/unix/apr_pools.c:2291
#6 0x7fe738f14aba in apr_table_mergen tables/apr_tables.c:746
#7 0x5578ad926a25 in ap_set_keepalive /home/ylavic/src/apache/httpd/trunk/modules/http/http_protocol.c:309
#8 0x5578ad93933f in ap_http_header_filter /home/ylavic/src/apache/httpd/trunk/modules/http/http_filters.c:1376
#9 0x5578ad98f7bd in ap_pass_brigade /home/ylavic/src/apache/httpd/trunk/server/util_filter.c:783
#10 0x5578ad9a67f3 in ap_content_length_filter /home/ylavic/src/apache/httpd/trunk/server/protocol.c:2046
#11 0x5578ad98f7bd in ap_pass_brigade /home/ylavic/src/apache/httpd/trunk/server/util_filter.c:783
#12 0x5578ad9405ae in ap_byterange_filter /home/ylavic/src/apache/httpd/trunk/modules/http/byterange_filter.c:463
#13 0x5578ad98f7bd in ap_pass_brigade /home/ylavic/src/apache/httpd/trunk/server/util_filter.c:783
#14 0x7fe7330e398b in ap_headers_output_filter /home/ylavic/src/apache/httpd/trunk/modules/metadata/mod_headers.c:891
#15 0x5578ad98f7bd in ap_pass_brigade /home/ylavic/src/apache/httpd/trunk/server/util_filter.c:783
#16 0x7fe732e32dba in session_output_filter /home/ylavic/src/apache/httpd/trunk/modules/session/mod_session.c:501
#17 0x5578ad98f7bd in ap_pass_brigade /home/ylavic/src/apache/httpd/trunk/server/util_filter.c:783
#18 0x5578ad9c8ee5 in default_handler /home/ylavic/src/apache/httpd/trunk/server/core.c:5188
#19 0x5578ad9431bb in ap_run_handler /home/ylavic/src/apache/httpd/trunk/server/config.c:170
#20 0x5578ad944941 in ap_invoke_handler /home/ylavic/src/apache/httpd/trunk/server/config.c:444
#21 0x5578ad92cc23 in ap_process_async_request /home/ylavic/src/apache/httpd/trunk/modules/http/http_request.c:463
#22 0x5578ad924d7c in ap_process_http_async_connection /home/ylavic/src/apache/httpd/trunk/modules/http/http_core.c:158
#23 0x5578ad925410 in ap_process_http_connection /home/ylavic/src/apache/httpd/trunk/modules/http/http_core.c:252
#24 0x5578ad97e04d in ap_run_process_connection /home/ylavic/src/apache/httpd/trunk/server/connection.c:42
#25 0x7fe735c7ef79 in process_socket /home/ylavic/src/apache/httpd/trunk/server/mpm/event/event.c:1097
#26 0x7fe735c856a0 in worker_thread /home/ylavic/src/apache/httpd/trunk/server/mpm/event/event.c:2386
#27 0x7fe738f7cef4 in dummy_worker threadproc/unix/thread.c:145
#28 0x7fe738e3eea6 in start_thread nptl/pthread_create.c:477
#29 0x7fe738d6ed4e in __clone (/lib/x86_64-linux-gnu/libc.so.6+0xfdd4e)
0x60600025acf0 is located 48 bytes inside of 64-byte region [0x60600025acc0,0x60600025ad00)
freed by thread T63 here:
#0 0x7fe7391ed277 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107277)
#1 0x7fe738f4e9e5 in pool_clear_debug memory/unix/apr_pools.c:1893
#2 0x7fe738f4ecb2 in pool_destroy_debug memory/unix/apr_pools.c:1956
#3 0x7fe738f4eeeb in apr_pool_destroy_debug memory/unix/apr_pools.c:2002
#4 0x5578ada2534b in ap_queue_info_push_pool /home/ylavic/src/apache/httpd/trunk/server/mpm_fdqueue.c:230
#5 0x7fe735c81412 in process_lingering_close /home/ylavic/src/apache/httpd/trunk/server/mpm/event/event.c:1686
#6 0x7fe735c7f9bc in process_socket /home/ylavic/src/apache/httpd/trunk/server/mpm/event/event.c:1255
#7 0x7fe735c856a0 in worker_thread /home/ylavic/src/apache/httpd/trunk/server/mpm/event/event.c:2386
#8 0x7fe738f7cef4 in dummy_worker threadproc/unix/thread.c:145
#9 0x7fe738e3eea6 in start_thread nptl/pthread_create.c:477
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883750 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since apr_[pre_]cleanup_register() functions are declared ((nonnull)) for
plain_cleanup_fn and child_cleanup_fn, the compiler (gcc-9 here) issues a
warning when we check them for !NULL is the code.
To preserve APR_POOL_DEBUG checks still with compilers that don't support
this __attribute__, let's work around this by checking NULL values afterward
for c, c->plain_cleanup_fn and c->child_cleanup_fn.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883749 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
'active' variable is never read/used before being set again to
pool->active on line 1436.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1878340 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
| |
only needed when APR_POOL_DEBUG is defined,
but can be aor should be called from app code.
Providing stubs allows the app code to stay the
same when running with or without debugging APR
lib (no need for app recompilation).
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1863217 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1856873 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
Avoids "conversion from 'size_t' to 'apr_uint32_t', possible loss" warnings.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1822357 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
| |
* memory/unix/apr_pools.c (apr_pool_get_tag): New function.
* test/testpools.c: Test it.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1817892 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
| |
* memory/unix/apr_pools.c
(allocator_lock, allocator_unlock): New helpers.
(apr_allocator_max_free_set, allocator_alloc, allocator_free): Use
allocator_lock() and allocator_unlock().
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1806296 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
| |
argument, for better scalability of the API.
Update apr_bucket_alloc_aligned_floor() from r1788335 accordingly.
Suggested by ivan.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1789947 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
allocators and pools, so axe apr_pool_alloc_order_set().
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1788376 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
apr_allocator_min_order_set() and apr_pool_alloc_order_set() to
respectively get the (system's) page size in use, set the minimum
allocation size for an allocator and the pool default allocation
size (expressed in 2^order pages).
Also allows for order-0 allocations (and pools), hence use index
MAX_INDEX (instead of index 0) to track oversized nodes.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1788346 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
would be allocated for the given size (including the header and alignment).
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1788334 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
global pool creation event. This ensures that the allocation
event from the cleanup registration written after the creation event.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1675982 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
don't try to emit any debug events after the debug log file handle
has been closed.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1675970 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
always emitted before allocation events and subpool destruction
events are emitted on pool clear/destroy for proper accounting.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1675967 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
| |
* memory/unix/apr_pools.c
(apr_pool_initialize): Add parent to debug header.
(apr_pool_log_event): Add parent to debug output.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1674566 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
| |
* use defined constants for in_use
* don't use C99's __func__
* improve abort message
* fix some confusion wrt the destroyed state
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1595549 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
APR pools after clearing or destroying pools that allocated larger
nodes.
When allocating nodes from the bucket allocator (<= 80k or 20 pages),
we would eagerly reuse *any* free node that is at least the minimum
size. Depending on the pool usage scheme, that extra memory would
never be used. This patch limits the node to approximate twice the
minimum.
* memory/unix/apr_pools.c
(allocator_alloc): When searching the buckets for free nodes, limit
the range to twice the starting index.
Submitted by: Stefan Fuhrmann <stefan fuhrmann wandisco com>
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1594729 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
| |
s/appropiate/appropriate/
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1594684 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
| |
Add new --enable-allocator-guard-pages configure option which works like
--enable-allocator-uses-mmap, but will also add inaccessible guard pages before
and after each memnode. This will result in higher ressource usage but allow
to find/protect against certain buffer overflow/overread bugs.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1593615 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Enabled by new configure option --enable-pool-concurrency-check.
Compared to pool-owner-debugging, this only detects cases where there is actual
contention between accesses. The advantage is that runtime costs should be
relatively low.
The diagnostic messages could still use some improvement.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1593614 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1559343 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
- avoid using a destroyed mutex in apr_pool_clear()
- if we create a sub-pool, we don't need to own the pool.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1481186 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
| |
apr_pool_create_unmanaged_ex()
PR: 54892
Submitted by: Valeriy V. Argunov <hzdbyte gmail com>
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1478934 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
| |
Run the pool owner check part only after pre-cleanups have been run, in
order to give them a chance to kill of any threads that may still be
accessing the pool.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1460184 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Actually this function has been mentioned in the docs for over 10 years
but has never been implemented.
Also consistently destroy the thread's pool when it exits normally, not only
on apr_thread_exit(). This was already done on OS2.
Other platforms than unix are untested.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1460182 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1460180 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Teach valgrind about apr pools, allocators, and bucket allocators
if --with-valgrind is passed to configure.
This has less impact on program behavior and performance than compiling
with complete pool-debugging. Even with valgrind support compiled in,
the performance impact if not running under valgrind should be minimal.
It may make sense to use pool-debugging together with valgrind support
because pool-debugging does not help with allocators and bucket
allocators.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1438957 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
| |
function is set.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1438940 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1130274 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1130270 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
[APR_POOL_DEBUG]: Catch NULL arguments which would lead to
strange segfaults later.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1082177 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
instead of malloc in apr_allocator_alloc(). This greatly reduces
memory fragmentation with malloc implementations (e.g. glibc) that
don't handle allocationss of a page-size-multiples in an efficient way.
It also makes apr_allocator_max_free_set() actually have some effect
on such platforms.
The handling of page sizes other than 4k seems like a lot of trouble for a
very small number of platforms, but there does not seem to be a reasonable
way to check this at compile time.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1072165 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
| |
current_free_index counts pages of size BOUNDARY_SIZE, but every node contains
index + 1 of such pages
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@990435 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
| |
Author: Mladen Turk <mturk@apache.org>
Date: Thu Apr 2 16:58:40 2009 +0000
Both cleanup and pre_cleanup can share the same free list.
Axe the free_pre_cleanups and use free_cleanups for both
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@990431 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
|
|
|
|
|
|
|
|
| |
- error handling issues
- use of uninitialized data
- null pointer dereference
- unused variables
- memory/fd leaks
- broken code in threadproc/beos/proc.c
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@979891 13f79535-47bb-0310-9956-ffa450edef68
|
|
|
|
| |
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@893840 13f79535-47bb-0310-9956-ffa450edef68
|