summaryrefslogtreecommitdiff
path: root/dbus/dbus-hash.c
Commit message (Collapse)AuthorAgeFilesLines
* dbus-hash: Add (AFL-2.1 OR GPL-2.0-or-later) AND TCL SPDX license identifierSimon McVittie2022-11-291-0/+1
| | | | | | | The TCL-derived code is under its own license, so the overall license of the file is (AFL-2.1 OR GPL-2.0-or-later) AND TCL. Signed-off-by: Simon McVittie <smcv@collabora.com>
* test: Unembed hash test from libdbus and move it into test/Simon McVittie2019-01-211-440/+0
| | | | | | | | This required exposing one additional internal symbol: _dbus_hash_table_ref(). I think that's a reasonable trade-off for not compiling this test into the library. Signed-off-by: Simon McVittie <smcv@collabora.com>
* dbus-hash: Attempt to update copyright holders from git historySimon McVittie2019-01-211-3/+8
| | | | | | This is in preparation for splitting the file, tests vs. non-tests. Signed-off-by: Simon McVittie <smcv@collabora.com>
* embedded tests: Conform to the same API for all testsSimon McVittie2018-12-171-1/+1
| | | | | | | | | This will make it possible to unify the wrapper code that runs them. I'm using a plain C string rather than a DBusString to make it more straightforward to carve out tests into their own executables. Signed-off-by: Simon McVittie <smcv@collabora.com>
* trivial: Remove trailing whitespace from copyright noticesSimon McVittie2018-12-171-10/+10
| | | | | | | | | | | | | | We don't usually mass-remove trailing whitespace from the actual source code because it would complicate cherry-picking bug fixes to older branches, but that reasoning doesn't really apply to the comments containing copyright and licensing notices. Removing trailing whitespace makes it much easier to move code around: we have a commit hook that rejects commits containing trailing whitespace, but that commit hook counts moving a file as a delete + add pair, so it objects to moving code that contains trailing whitespace. Signed-off-by: Simon McVittie <smcv@collabora.com>
* DBusHash: Program a bit more defensivelySimon McVittie2018-12-031-5/+23
| | | | | | | | | In particular, the assertions that bucket >= table->buckets and bucket <= &table->buckets[table->n_buckets - 1] catch the bug fixed by the previous commit, by ensuring that bucket is somewhere inside the new array of buckets. Signed-off-by: Simon McVittie <smcv@collabora.com>
* DBusHash: Recalculate bucket used if the table is rebuiltSimon McVittie2018-12-031-6/+35
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Hash buckets are simply entries in an array owned by the hash table, so every time the hash table's array of buckets is reallocated, we must invalidate all pointers to buckets and recalculate them to point into the new array of buckets. This was not always done. Luckily, we appear to have avoided causing any actual memory corruption like this. The only place where we reallocate the array of buckets is in rebuild_table(), which is only called by add_allocated_entry(), which is only called by add_entry(), which is only called by find_generic_function() when create_if_not_found is true. find_generic_function(), in turn, is only called by the table->find_function() implementations. The table->find_function() implementations have an optional "out" parameter which returns a pointer to the hash bucket in which the returned entry would be found. It is set in find_generic_function() for existing entries, or in add_allocated_entry() if a new entry is created; after that it is returned through callers unchanged until the caller of table->find_function() is reached. The only callers that make use of the "out" parameter in practice are _dbus_hash_iter_lookup(), to populate a DBusHashIter, and the _dbus_hash_table_remove_TYPE() family, to pass it to remove_entry(). We can ignore the _dbus_hash_table_remove_TYPE() family for two reasons: they call the find function with create_if_not_found set to FALSE, which never reallocates the hash table, and they do not store the pointer to the bucket in the long-term. So we only need to consider _dbus_hash_iter_lookup(). It is documented to be unsafe to add hash entries while a DBusHashIter is open, and only adding a hash entry can trigger rebuild_table(); so we can assume that if _dbus_hash_iter_lookup() returns a valid bucket, it remains valid forever. The remaining case that must be considered is whether reallocation can occur after setting the "out" parameter for the bucket, but before returning it to _dbus_hash_iter_lookup(). We can see that it can: we call rebuild_table() after recalculating the correct bucket. If we do, and it actually causes a rebuild, then we must recalculate the bucket accordingly. Looking at the worst-case impact of this bug, if it is going to cause any problem, it would only be when _dbus_hash_iter_lookup() is called with create_if_not_found set true. This makes three uses of the bucket: it stores it in the DBusHashTableIter, it calculates the next bucket by finding the offset of the bucket in table->buckets and advancing by one pointer, and it makes an assertion that should be tautologous, enforcing that the next bucket corresponds to what it should. When running under the AddressSanitizer, which makes allocations in widely spaced regions of memory, on a 32-bit platform, we could (and indeed do) find that the tautologous assertion fails. The current bucket returned from the "out" parameter is a pointer into the old value of table->buckets. If it's far enough before or after the new table->buckets in the address space, then the offset in next_bucket could overflow a 32-bit integer, resulting in the assertion no longer being true. The next commit will add extra assertions, which reproduce the bug even without AddressSanitizer. In production code without assertions, the impact is that the ->bucket and ->next_bucket members of the DBusHashIter can be invalid. They are used in _dbus_hash_iter_next() and _dbus_hash_iter_remove_entry(). However, the only callers of _dbus_hash_iter_lookup() outside test code are in bus/containers.c, and neither calls either of those functions, so we dodge that bullet. Signed-off-by: Simon McVittie <smcv@collabora.com>
* Prefer to use _dbus_test_fatal() for assertion failures in testsSimon McVittie2017-11-151-4/+4
| | | | | | | | | | | | This is a little more self-documenting - it justifies why it's acceptable to fail hard on out-of-memory conditions. _dbus_test_fatal() isn't compiled unless we are compiling embedded tests, so compiling with embedded tests disabled provides reasonable confidence that we aren't using _dbus_test_fatal() inappropriately. Reviewed-by: Philip Withnall <withnall@endlessm.com> Signed-off-by: Simon McVittie <smcv@collabora.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=103601
* Embedded tests: Emit TAP diagnostics instead of printfSimon McVittie2017-11-151-3/+4
| | | | | | Reviewed-by: Philip Withnall <withnall@endlessm.com> Signed-off-by: Simon McVittie <smcv@collabora.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=103601
* dbus-hash: Fix memory leaks in internal hash table testsPhilip Withnall2017-02-161-98/+118
| | | | | | | | | | | | This includes fixing a memory leak in _dbus_hash_iter_lookup(), which is not one of the unit tests; but it is only ever called from the unit tests, so this is not a user-facing leak. Coverity IDs: 54730, 54740 Signed-off-by: Philip Withnall <withnall@endlessm.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=99793 Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
* Revert "dbus-hash: Fix memory leaks in internal hash table tests"Simon McVittie2017-02-141-111/+97
| | | | | | | | | | | This reverts commit 5f0cd1a24ca392434f4a690397d2f509b8c65af5, which appears to trigger a timeout: dbus-daemon[26876]: Activating service name='org.freedesktop.DBus.TestSuiteEchoService' requested by ':1.2415' (uid=1000 pid=26876 comm=".../bus/.libs/test-bus ") dbus-daemon[26876]: Failed to activate service 'org.freedesktop.DBus.TestSuiteEchoService': timed out (service_start_timeout=25000ms) dbus-daemon[26876]: Did not expect error org.freedesktop.DBus.Error.TimedOut Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
* dbus-hash: Fix memory leaks in internal hash table testsPhilip Withnall2017-02-131-97/+111
| | | | | | | | | | | This includes fixing a memory leak in _dbus_hash_iter_lookup(), which is not one of the unit tests; but it is only ever called from the unit tests, so this is not a user-facing leak. Coverity IDs: 54730, 54740 Signed-off-by: Philip Withnall <withnall@endlessm.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=99793 Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
* dbus-hash: Fix a potential shift by a negative integerPhilip Withnall2017-02-131-1/+2
| | | | | | | | | | | | | | | | | | As a hash table becomes unbelievably large and full, the down_shift tends towards 0. The overflow detection code in rebuild_table() does not prevent down_shift becoming negative, which then causes undefined behaviour in RANDOM_INDEX for int-keyed tables. Note that this can only happen with approaching INT_MAX entries in the hash table, at which point we’ve almost certainly hit OOM somewhere, so this is vanishingly unlikely to happen. This is why I can’t add a test for the bug. As always, thanks to Coverity. Coverity ID: 54682 Bug: https://bugs.freedesktop.org/show_bug.cgi?id=99641 Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
* Move _dbus_hash_table_{to,from}_array out of #ifdef DBUS_ENABLE_EMBEDDED_TESTSSimon McVittie2016-02-121-129/+129
| | | | Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
* Add new functions _dbus_hash_table_to_array() and ↵Ralf Habacker2016-02-121-0/+129
| | | | | | | | | _dbus_hash_table_from_array() from related activation code. These functions are required for dbus-run-session. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92899 Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
* Replace some runtime assertions with compile-time assertionsSimon McVittie2014-09-151-3/+3
| | | | | | | | | This requires a little bit of code re-ordering, because _DBUS_STATIC_ASSERT can appear anywhere that a variable declaration would be valid, i.e. not after executable code. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=83767 Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
* tests to embedded tests: replaced in libdbusChengwei Yang2013-06-281-2/+2
| | | | | | Signed-off-by: Chengwei Yang <chengwei.yang@intel.com> Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=66291
* DBUS_HASH_TWO_STRINGS, DBUS_HASH_POINTER: remove, unusedSimon McVittie2012-02-101-365/+0
| | | | | | Bug: https://bugs.freedesktop.org/show_bug.cgi?id=39759 Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk> Reviewed-by: Lennart Poettering <lennart@poettering.net>
* Add _DBUS_STATIC_ASSERT (based on GLib's G_STATIC_ASSERT) and use itSimon McVittie2011-08-111-0/+2
| | | | | Bug: https://bugs.freedesktop.org/show_bug.cgi?id=39636 Reviewed-by: Will Thompson <will.thompson@collabora.co.uk>
* Don't truncate pointers on Windows x64 platformFridrich Štrba2010-05-031-22/+22
|
* Consistently include <config.h> in all C source files and never in header files.Marcus Brinkmann2010-03-191-0/+1
|
* Bug 21161 - Update the FSF addressTobias Mueller2009-07-101-1/+1
| | | | | | No comment. Signed-off-by: Colin Walters <walters@verbum.org>
* 2007-07-13 Havoc Pennington <hp@redhat.com>Havoc Pennington2007-07-141-1/+1
| | | | * Add indent-tabs-mode: nil to all file headers.
* * s/D-BUS/D-Bus/gJohn (J5) Palmieri2006-08-031-2/+2
|
* * bus/bus.c: (bus_context_reload_config): Flush the user database cache onSjoerd Simons2006-03-061-0/+16
| | | | | | | | | | | config reload. * bus/dbus-daemon.1.in: Also note that SIGHUP flushes the user/group information caches * dbus/dbus-hash.c: (_dbus_hash_table_remove_all): * dbus/dbus-hash.h: Add function to remove all entries from a hash table * dbus/dbus-userdb.c: (_dbus_user_database_flush): * dbus/dbus-userdb.h: Add function to flush all user/group information caches.
* 2005-01-16 Havoc Pennington <hp@redhat.com>Havoc Pennington2005-01-171-0/+25
| | | | | | | | | | | | | | | | | | | | | | | | This is about it on what can be disabled/deleted from libdbus easily, back below 150K anyhow. Deeper cuts are more work than just turning the code off as I've done here. * dbus/dbus-marshal-basic.c (_dbus_pack_int32): we don't need the signed int convenience funcs * dbus/dbus-internals.c (_dbus_verbose_real): omit when not in verbose mode * dbus/dbus-string-util.c, dbus/dbus-string.c: more breaking things out of libdbus * dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-util.c: same * dbus/dbus-hash.c: purge the TWO_STRINGS crap (well, make it tests-enabled-only, though it should probably be deleted) * dbus/dbus-message-util.c: same stuff * dbus/dbus-auth-util.c: same stuff
* 2004-08-09 Havoc Pennington <hp@redhat.com>Havoc Pennington2004-08-101-1/+1
| | | | | * COPYING: switch to Academic Free License version 2.1 instead of 2.0, to resolve complaints about patent termination clause.
* 2003-12-02 Richard Hult <richard@imendio.com>Richard Hult2003-12-021-1/+1
| | | | | * Update AFL version to 2.0 throughout the source files to reflect the update that was done a while ago.
* 2003-11-26 Mikael Hallendal <micke@imendio.com>Mikael Hallendal2003-11-271-1/+4
| | | | | | * bus/*.[ch]: * dbus/*.[ch]: * glib/*.[ch]: Made ref functions return the pointer
* 2003-09-07 Havoc Pennington <hp@pobox.com>Havoc Pennington2003-09-071-0/+1
| | | | * Make Doxygen contented.
* 2003-08-18 Havoc Pennington <hp@redhat.com>Havoc Pennington2003-08-181-11/+18
| | | | | | | | | | | | | | | | | | | | | | | | * dbus/dbus-hash.c (_dbus_hash_table_insert_two_strings): fix * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix dumb bug created earlier (wrong order of args to decode_header_data()) * tools/dbus-send.c: port * tools/dbus-print-message.c (print_message): port * test/data/*messages: port all messages over * dbus/dbus-message-builder.c: support including message type * bus/driver.c: port over * bus/dispatch.c: port over to new stuff * dbus/dbus-connection.c (_dbus_connection_new_for_transport): rename disconnect signal to "Disconnected"
* 2003-08-17 Havoc Pennington <hp@pobox.com>Havoc Pennington2003-08-181-88/+290
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This doesn't compile yet, but syncing up so I can hack on it from work. What are branches for if not broken code? ;-) * dbus/dbus-protocol.h: remove DBUS_HEADER_FIELD_NAME, add DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER, DBUS_HEADER_FIELD_ERROR_NAME * dbus/dbus-hash.c: Introduce DBUS_HASH_TWO_STRINGS as hack to use for the interface+member pairs (string_hash): change to use g_str_hash algorithm (find_direct_function, find_string_function): refactor these to share most code. * dbus/dbus-message.c: port all of this over to support interface/member fields instead of name field * dbus/dbus-object-registry.c: port over * dbus/dbus-string.c (_dbus_string_validate_interface): rename from _dbus_string_validate_name * bus/dbus-daemon-1.1: change file format for the <deny>/<allow> stuff to match new message naming scheme * bus/policy.c: port over * bus/config-parser.c: parse new format
* 2003-05-04 Havoc Pennington <hp@pobox.com>Havoc Pennington2003-05-051-2/+9
| | | | | | | | | | | | | | | | | | * dbus/dbus-message-handler.c (_dbus_message_handler_test): add unit test * dbus/dbus-marshal.c (_dbus_demarshal_string_array): fix this function, which assumed length was in # of strings, not bytes * dbus/dbus-message.c (_dbus_message_test): add tests for some missing coverage * dbus/dbus-connection.c (_dbus_connection_queue_received_message): disable function for now, we are only using it in test mode * dbus/dbus-message.c (_dbus_message_loader_queue_messages): remove a mistaken FIXME
* 2003-04-10 Havoc Pennington <hp@redhat.com>Havoc Pennington2003-04-111-74/+182
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * dbus/dbus-connection.c (dbus_connection_flush): don't spin on the connection if it's disconnected * bus/activation.c (bus_activation_service_created): use new transaction features to roll back removal of pending activation if we don't successfully create the service after all. Don't remove pending activation if the function fails. * dbus/dbus-list.c (_dbus_list_insert_before_link) (_dbus_list_insert_after_link): new code to facilitate services.c fixes * dbus/dbus-hash.c (_dbus_hash_table_insert_string_preallocated): new functionality, so we can preallocate the ability to insert into a hash table. * bus/connection.c (bus_transaction_add_cancel_hook): new function allowing us to put custom hooks in a transaction to be used for cancelling said transaction * doc/dbus-specification.sgml: add some discussion of secondary service owners, and disallow zero-length service names * bus/services.c (bus_registry_acquire_service): new function, splits out part of bus_driver_handle_acquire_service() and fixes a bug where we didn't remove the service doing the acquiring from the secondary queue if we failed to remove the current owner from the front of the queue.
* 2003-03-23 Havoc Pennington <hp@pobox.com>Havoc Pennington2003-03-231-1/+142
| | | | | | | | | | * bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny policies code * dbus/dbus-hash.h: add ULONG hash keys * dbus/dbus-sysdeps.c (_dbus_get_groups): new (_dbus_get_group_id): new function
* 2003-02-18 Joe Shaw <joe@assbarn.com>Joe Shaw2003-02-181-35/+55
| | | | | | | | | | | | | | | | | | | | | | * dbus/dbus-auth.c (handle_server_data_stupid_test_mech): Just get credentials from our currently running process. (get_word): Fix a buglet where we were copying the entire length instead of relative to our position. * dbus/dbus-hash.c (_dbus_hash_test): Don't try to allocate the keys on the stack... it's 640k of data. * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): Always read the credentials byte off the socket, even if we don't have SO_PEERCRED. (_dbus_poll): Implement poll() using select() for systems which don't have it. * glib/test-dbus-glib.c (main): Print out an error if no parameters are given. * test/data/auth/fallback.auth-script: Added. Tests that a client can fallback to a secondary auth mechanism if the first fails.
* 2003-02-16 Alexander Larsson <alexl@redhat.com>Alexander Larsson2003-02-161-3/+25
| | | | | * dbus/dbus-hash.c (_dbus_hash_table_unref): Actually free keys and values when destroying hashtable.
* 2003-01-05 Havoc Pennington <hp@pobox.com>Havoc Pennington2003-01-061-6/+103
| | | | | | | | | | | | | | | | | | * bus/connection.c: implement routines for handling connections, first thing is keeping a list of owned services on each connection and setting up watches etc. * bus/services.c: implement a mapping from service names to lists of connections * dbus/dbus-hash.c: add DBUS_HASH_POINTER * dbus/dbus-threads.c (dbus_static_mutex_lock): add functions to use static mutexes for global data * dbus/dbus-connection.c (dbus_connection_set_data): add new collection of functions to set/get application-specific data on the DBusConnection.
* 2002-12-24 Havoc Pennington <hp@pobox.com>Havoc Pennington2002-12-241-51/+187
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * glib/dbus-gthread.c: fix include * glib/dbus-glib.h: rename DBusMessageHandler for now. I think glib API needs to change, though, as you don't want to use DBusMessageFunction, you want to use the DBusMessageHandler object. Probably dbus_connection_open_with_g_main_loop() and dbus_connection_setup_g_main_loop() or something like that (but think of better names...) that just create a connection that has watch/timeout functions etc. already set up. * dbus/dbus-connection.c (dbus_connection_send_message_with_reply): new function just to show how the message handler helps us deal with replies. * dbus/dbus-list.c (_dbus_list_remove_last): new function * dbus/dbus-string.c (_dbus_string_test): free a string that wasn't * dbus/dbus-hash.c: use memory pools for the hash entries (rebuild_table): be more paranoid about overflow, and shrink table when we can (_dbus_hash_test): reduce number of sprintfs and write valid C89. Add tests for case where we grow and then shrink the hash table. * dbus/dbus-mempool.h, dbus/dbus-mempool.c: memory pools * dbus/dbus-connection.c (dbus_connection_register_handler) (dbus_connection_unregister_handler): new functions * dbus/dbus-message.c (dbus_message_get_name): new * dbus/dbus-list.c: fix docs typo * dbus/dbus-message-handler.h, dbus/dbus-message-handler.c: an object representing a handler for messages.
* 2002-12-11 Havoc Pennington <hp@pobox.com>Havoc Pennington2002-12-121-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | * dbus/dbus-types.h: add dbus_unichar * dbus/dbus-internals.c (_dbus_verbose): use _dbus_getenv * dbus/dbus-connection.c (dbus_connection_send_message): return TRUE on success * dbus/dbus-transport.c: include dbus-watch.h * dbus/dbus-connection.c: include dbus-message-internal.h * HACKING: add file with coding guidelines stuff. * dbus/dbus-string.h, dbus/dbus-string.c: Encapsulate all string handling here, for security purposes (as in vsftpd). Not actually using this class yet. * dbus/dbus-sysdeps.h, dbus/dbus-sysdeps.c: Encapsulate all system/libc usage here, as in vsftpd, for ease of auditing (and should also simplify portability). Haven't actually moved all the system/libc usage into here yet.
* 2002-11-23 Havoc Pennington <hp@pobox.com>Havoc Pennington2002-11-231-4/+23
| | | | | | | | | | | | | | | | | | * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN _DBUS_INT_MAX * dbus/dbus-test.c (main): add list test, and include dbus-test.h as intended * dbus/dbus-hash.c (_dbus_hash_table_remove_string) (_dbus_hash_table_remove_int): return value indicates whether the entry existed to remove * dbus/dbus-list.c: add linked list utility class, with docs and tests * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket array sometimes.
* 2002-11-23 Havoc Pennington <hp@pobox.com>Havoc Pennington2002-11-231-5/+9
| | | | | | | | | | * Doxyfile.in (INCLUDE_FILE_PATTERNS): expand DBUS_BEGIN_DECLS/ DBUS_END_DECLS to nothing, that should fix this once and for all * Doxyfile.in (JAVADOC_AUTOBRIEF): set to YES * dbus/dbus-message.c, dbus/dbus-hash.c: add some missing @brief
* 2002-11-23 Havoc Pennington <hp@pobox.com>Havoc Pennington2002-11-231-3/+4
| | | | | | | | | | * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS to avoid confusing Doxygen * dbus/dbus-hash.c: @} not }@ * dbus/dbus-message.c (struct DBusMessage): split out internals docs
* 2002-11-23 Havoc Pennington <hp@pobox.com>Havoc Pennington2002-11-231-842/+1143
| | | | | | | | | | | | | | | | | | | | | * configure.in: pile on more warning flags if using gcc * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have to document static functions * configure.in: add summary to end of configure so it looks nice and attractive * dbus/dbus-hash.c: finish implementation and write unit tests and docs * configure.in: add --enable-tests to enable unit tests * dbus/dbus-test.c: test program to run unit tests for all files in dbus/*, initially runs a test for dbus-hash.c * dbus/dbus-internals.h: file to hold some internal utility stuff
* 2002-11-22 Havoc Pennington <hp@redhat.com>Havoc Pennington2002-11-221-0/+1083
| | | | | | | * dbus/dbus-hash.c: copy in Tcl hash table, not yet "ported" away from Tcl * dbus/dbus-types.h: header for types such as dbus_bool_t
* initial import of "dbus" skeletonHavoc Pennington2002-11-211-0/+0