mirror of
git://git.psyced.org/git/psyclpc
synced 2024-08-15 03:20:16 +00:00
initial git creation
This commit is contained in:
commit
2ede0de60e
278 changed files with 230984 additions and 0 deletions
14
mudlib/uni-crasher/README
Normal file
14
mudlib/uni-crasher/README
Normal file
|
@ -0,0 +1,14 @@
|
|||
This directory holds a LPC object which runs a stress test against the driver:
|
||||
it calls random efuns with random arguments and keeps a log of what has been
|
||||
called.
|
||||
|
||||
It was written for the Unitopia mudlib (and thusly uses some of their
|
||||
simul-efuns). To use it, copy secure.inc into the secure/simul_efun
|
||||
directory first.
|
||||
|
||||
crasher.c : the test object
|
||||
crashleak.c: a variant of the crasher object looking for memory leaks.
|
||||
secure.inc : a replacement for the original secure/simul_efun/secure.inc,
|
||||
so that the security-sensitive functions can be tested, too.
|
||||
|
||||
Written by Andreas "Menaures" Klauer.
|
831
mudlib/uni-crasher/crasher.c
Normal file
831
mudlib/uni-crasher/crasher.c
Normal file
|
@ -0,0 +1,831 @@
|
|||
/*
|
||||
crasher: Standardversion (Menaures 07.12.01)
|
||||
|
||||
ANLEITUNG:
|
||||
|
||||
1. Bei dem Define DEBUGGER den eigenen Real-Namen angeben
|
||||
|
||||
2. Define VERBOSE auskommentieren, falls nicht bereits so.
|
||||
VERBOSE kann genutzt werden, wenn gesicherte Dateien einen
|
||||
Crash ausloesen und die genaue Zeile gesucht wird.
|
||||
(VERBOSE gibt vor jedem einzelnen Aufruf momentane
|
||||
Datei und Zeile per debug_message aus).
|
||||
|
||||
3. Wenn bereits aufgenommene Dateien existieren, das EFuns und
|
||||
Values-Array NICHT modifizieren, bzw. nicht die Positionen
|
||||
der einzelnen Elemente aendern - sonst werden die aufgezeichneten
|
||||
Dateien unbrauchbar. Ebenso koennen nach solchen Modifikationen
|
||||
aufgenommene Dateien nicht mehr von alten Versionen des Crashers
|
||||
abgespielt werden.
|
||||
|
||||
Wer andere Values / Closures haben moechte, modifiziere die
|
||||
entsprechenden Arrays, speichere den Crasher unter einem anderen
|
||||
Filenamen und mache einen eindeutigen Eintrag im Header...
|
||||
|
||||
record:
|
||||
|
||||
record(file) speichert Ausfuehrungsablaeufe in Dateien namens
|
||||
file_xxxx, wobei xxxx eine Durchlaufnummer ist. Das Objekt
|
||||
braucht fuer diese Dateien logischerweise Schreibrecht.
|
||||
|
||||
Die aufgenommenen Dateien werden nach ihrer Erstellung automatisch
|
||||
ausgefuehrt. Fuehrt dies zu einem Crash, kann man das ganze einfach
|
||||
nochmals abspielen.
|
||||
|
||||
replay:
|
||||
|
||||
replay(file) spielt aufgenommene Dateien ab, fuehrt sie also aus.
|
||||
Dies ist dazu da, um Crashes, die dieses Objekt erzeugt, zu
|
||||
reproduzieren. Statt file wird file_xxxx eingelesen, wobei xxxx
|
||||
eine Durchlaufnummer ist.
|
||||
|
||||
execute_file:
|
||||
|
||||
Mit execute_file(file) kann man eine Datei gezielt ausfuehren.
|
||||
Dazu gibt man den echten Dateinamen der Datei an, inklusive
|
||||
Durchlaufnummer.
|
||||
|
||||
debug_query:
|
||||
|
||||
Mit debug_query(file, line) kann man abfragen, was in der Datei
|
||||
file in Zeile line ausgefuehrt werden wuerde - also welche
|
||||
Closure mit welchen Argumenten.
|
||||
|
||||
Hierzu muss der eigene Name als DEBUGGER definiert sein.
|
||||
|
||||
debug_exec:
|
||||
|
||||
Mit debug_exec(file, line) wird die angegebene Zeile in der
|
||||
Datei ausgefuehrt. Dadurch kann gezielt festgestellt werden,
|
||||
ob der einzelne Aufruf den Crash ausgeloest hat.
|
||||
|
||||
|
||||
Crash-Grund finden:
|
||||
|
||||
Bringt der Crasher den Driver zum Absturz, zunaechst den Driver
|
||||
neu starten und mit execute_file das zuletzt aufgenommene File
|
||||
abspielen.
|
||||
|
||||
Bringt das den Driver zum Crash, den gleichen Vorgang mit
|
||||
aktiviertem VERBOSE wiederholen, um die Zeilennummer herauszufinden.
|
||||
|
||||
Hat man erst einmal die Zeilennummer, laesst sich per debug_query
|
||||
herausfinden, was ausgefuehrt werden, und mit debug_exec pruefen,
|
||||
ob es wirklich der Ausloeser war.
|
||||
|
||||
Kann der Crash auf diese Weise nicht reproduziert werden, kann man
|
||||
einmal versuchen, alle aufgenommenen Dateien mit replay abzuspielen;
|
||||
fuehrt das zu keinem Crash, wurde der Crash nicht durch einen
|
||||
bestimmten Aufruf (oder eine bestimmte Folge selbiger) ausgeloest,
|
||||
sondern hat einen anderen Grund, der genauer untersucht werden muss.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define DEBUGGER "menaures"
|
||||
#include <debug.h>
|
||||
|
||||
// #define VERBOSE // Aktivieren, wenn man die crashausloesende Zeile sucht
|
||||
|
||||
#define MAX_ARGS 5
|
||||
#define DELAY 4
|
||||
#define ITERATIONS 1000
|
||||
|
||||
mixed execute;
|
||||
mixed efuns;
|
||||
mixed values;
|
||||
mixed names;
|
||||
|
||||
void record(string file);
|
||||
|
||||
void reset_all()
|
||||
{
|
||||
catch(
|
||||
|
||||
execute = 0,
|
||||
|
||||
( efuns =
|
||||
({
|
||||
#'Name,
|
||||
#'[,
|
||||
#'abs,
|
||||
#'abs_path,
|
||||
#'acos,
|
||||
#'add_action,
|
||||
#'add_dot_to_msg,
|
||||
// #'add_verb,
|
||||
// #'add_xverb,
|
||||
#'all_environment,
|
||||
#'all_inventory,
|
||||
#'allocate,
|
||||
// #'allocate_mapping,
|
||||
#'and_bits,
|
||||
#'apply,
|
||||
#'arr_delete,
|
||||
#'asin,
|
||||
// #'assoc,
|
||||
#'atan,
|
||||
#'atan2,
|
||||
#'attach_erq_demon,
|
||||
#'auto_owner_search,
|
||||
#'binary_message,
|
||||
#'bind_lambda,
|
||||
// #'break_point,
|
||||
#'call_other,
|
||||
#'call_out,
|
||||
#'call_out_info,
|
||||
#'call_resolved,
|
||||
#'caller_stack,
|
||||
#'caller_stack_depth,
|
||||
#'capitalize,
|
||||
#'cat,
|
||||
#'catch,
|
||||
#'ceil,
|
||||
#'center,
|
||||
#'clear_bit,
|
||||
#'clock,
|
||||
#'clone_object,
|
||||
#'clonep,
|
||||
// #'clones,
|
||||
#'closurep,
|
||||
#'command,
|
||||
#'command_stack,
|
||||
#'command_stack_depth,
|
||||
#'cond_present,
|
||||
#'convert_message,
|
||||
#'convert_umlaute,
|
||||
#'copies,
|
||||
#'copy,
|
||||
#'copy_bits,
|
||||
#'copy_file,
|
||||
// #'copy_mapping,
|
||||
#'cos,
|
||||
#'count_bits,
|
||||
#'crypt,
|
||||
#'ctime,
|
||||
// #'db_affected_rows,
|
||||
// #'db_close,
|
||||
// #'db_coldefs,
|
||||
// #'db_connect,
|
||||
// #'db_conv_string,
|
||||
// #'db_error,
|
||||
// #'db_exec,
|
||||
// #'db_fetch,
|
||||
// #'db_handles,
|
||||
// #'db_insert_id,
|
||||
#'debug_info,
|
||||
#'debug_message,
|
||||
#'deep_copy,
|
||||
#'deep_inventory,
|
||||
#'deep_present,
|
||||
#'dein,
|
||||
#'deinem,
|
||||
#'deinen,
|
||||
#'deines,
|
||||
#'dem,
|
||||
#'den,
|
||||
#'der,
|
||||
#'des,
|
||||
#'destruct,
|
||||
#'diesem,
|
||||
#'diesen,
|
||||
#'dieser,
|
||||
#'dieses,
|
||||
#'disable_commands,
|
||||
#'domain2map,
|
||||
#'ed,
|
||||
// #'efun308,
|
||||
#'ein,
|
||||
#'einem,
|
||||
#'einen,
|
||||
#'eines,
|
||||
#'enable_commands,
|
||||
#'environment,
|
||||
#'er,
|
||||
#'exec,
|
||||
#'execute_command,
|
||||
#'exp,
|
||||
#'expand_define,
|
||||
#'explode,
|
||||
#'export_uid,
|
||||
#'extern_call,
|
||||
// #'extract,
|
||||
// #'file_name,
|
||||
#'file_path,
|
||||
#'file_size,
|
||||
#'file_time,
|
||||
#'filter,
|
||||
// #'filter_array,
|
||||
#'filter_indices,
|
||||
// #'filter_mapping,
|
||||
#'filter_objects,
|
||||
#'find_call_out,
|
||||
#'find_living,
|
||||
#'find_object,
|
||||
#'find_player,
|
||||
#'first_inventory,
|
||||
#'floatp,
|
||||
#'floor,
|
||||
#'format_seconds,
|
||||
#'format_vseconds,
|
||||
#'funcall,
|
||||
#'function_exists,
|
||||
#'functionlist,
|
||||
#'garbage_collection,
|
||||
#'get_align_string,
|
||||
#'get_dir,
|
||||
#'get_error_file,
|
||||
#'get_eval_cost,
|
||||
#'get_extra_wizinfo,
|
||||
#'get_genitiv,
|
||||
#'get_type_info,
|
||||
#'get_unique_string,
|
||||
#'geteuid,
|
||||
#'getuid,
|
||||
#'gmtime,
|
||||
#'heart_beat_info,
|
||||
#'ihm,
|
||||
#'ihn,
|
||||
#'ihr,
|
||||
#'ihrem,
|
||||
#'ihren,
|
||||
#'ihres,
|
||||
#'implode,
|
||||
#'inherit_list,
|
||||
#'input_to,
|
||||
// #'insert_alist,
|
||||
#'interactive,
|
||||
// #'intersect_alist,
|
||||
#'intp,
|
||||
#'invert_bits,
|
||||
#'ist,
|
||||
#'lambda,
|
||||
#'last_bit,
|
||||
#'last_instructions,
|
||||
#'left,
|
||||
#'limited,
|
||||
#'liste,
|
||||
#'living,
|
||||
#'load_name,
|
||||
#'load_object,
|
||||
#'localtime,
|
||||
#'log,
|
||||
#'log_file,
|
||||
#'lower_case,
|
||||
#'m_allocate,
|
||||
#'m_contains,
|
||||
#'m_delete,
|
||||
#'m_indices,
|
||||
#'m_reallocate,
|
||||
// #'m_sizeof,
|
||||
#'m_values,
|
||||
#'make_shared_string,
|
||||
#'map,
|
||||
#'map2domain,
|
||||
// #'map_array,
|
||||
#'map_indices,
|
||||
// #'map_mapping,
|
||||
#'map_object,
|
||||
#'map_objects,
|
||||
// #'mapping_contains,
|
||||
#'mappingp,
|
||||
#'max,
|
||||
#'md5,
|
||||
#'member,
|
||||
// #'member_array,
|
||||
#'min,
|
||||
#'mixed2str,
|
||||
#'mixed_to_closure,
|
||||
#'mkdir,
|
||||
#'mkmapping,
|
||||
#'move_object,
|
||||
#'negate,
|
||||
#'next_bit,
|
||||
#'next_inventory,
|
||||
#'not_alone,
|
||||
#'notify_fail,
|
||||
#'object_info,
|
||||
#'object_name,
|
||||
#'object_time,
|
||||
#'objectp,
|
||||
#'or_bits,
|
||||
// #'order_alist,
|
||||
#'parse_com,
|
||||
#'parse_com_error,
|
||||
#'parse_com_error_string,
|
||||
#'player_exists,
|
||||
#'player_present,
|
||||
#'playerp,
|
||||
#'plural,
|
||||
#'pointerp,
|
||||
#'pol2xy,
|
||||
#'pow,
|
||||
#'present,
|
||||
#'present_clone,
|
||||
#'previous_object,
|
||||
#'printf,
|
||||
#'process_string,
|
||||
#'program_name,
|
||||
#'program_time,
|
||||
#'query_actions,
|
||||
// #'query_akkusativ,
|
||||
#'query_command,
|
||||
// #'query_dativ,
|
||||
#'query_deklin,
|
||||
#'query_deklin_adjektiv,
|
||||
#'query_deklin_ein_adjektiv,
|
||||
#'query_deklin_name,
|
||||
// #'query_dekliniert,
|
||||
#'query_editing,
|
||||
// #'query_genitiv,
|
||||
#'query_idle,
|
||||
// #'query_imp_port,
|
||||
#'query_input_pending,
|
||||
#'query_ip_name,
|
||||
#'query_ip_number,
|
||||
#'query_limits,
|
||||
#'query_living_name,
|
||||
#'query_livings,
|
||||
#'query_load_average,
|
||||
#'query_mud_port,
|
||||
#'query_notify_fail,
|
||||
#'query_once_interactive,
|
||||
#'query_pronom,
|
||||
#'query_real_player_level,
|
||||
#'query_shadowing,
|
||||
#'query_snoop,
|
||||
#'query_udp_port,
|
||||
#'query_up_time,
|
||||
#'query_verb,
|
||||
#'quote,
|
||||
#'raise_error,
|
||||
#'random,
|
||||
#'read_bytes,
|
||||
#'read_file,
|
||||
#'real_time_diff,
|
||||
#'referencep,
|
||||
#'regexp,
|
||||
#'regexplode,
|
||||
#'regreplace,
|
||||
#'remove_action,
|
||||
#'remove_call_out,
|
||||
#'remove_input_to,
|
||||
#'remove_interactive,
|
||||
#'rename,
|
||||
#'rename_object,
|
||||
#'replace_program,
|
||||
#'restore_object,
|
||||
#'restore_value,
|
||||
#'right,
|
||||
#'rm,
|
||||
#'rmdir,
|
||||
#'round,
|
||||
#'rusage,
|
||||
#'save_object,
|
||||
#'save_value,
|
||||
#'say,
|
||||
#'search_object,
|
||||
#'sein,
|
||||
#'seinem,
|
||||
#'seinen,
|
||||
#'seines,
|
||||
#'send_erq,
|
||||
// #'send_imp,
|
||||
#'send_udp,
|
||||
// #'set_auto_include_string,
|
||||
#'set_bit,
|
||||
#'set_buffer_size,
|
||||
#'set_combine_charset,
|
||||
#'set_connection_charset,
|
||||
#'set_driver_hook,
|
||||
#'set_environment,
|
||||
#'set_extra_wizinfo,
|
||||
#'set_extra_wizinfo_size,
|
||||
#'set_heart_beat,
|
||||
#'set_is_wizard,
|
||||
#'set_light,
|
||||
#'set_limits,
|
||||
#'set_living_name,
|
||||
#'set_modify_command,
|
||||
#'set_next_reset,
|
||||
#'set_prompt,
|
||||
#'set_this_object,
|
||||
#'set_this_player,
|
||||
#'seteuid,
|
||||
#'sgn,
|
||||
#'shadow,
|
||||
#'short_format_seconds,
|
||||
#'short_format_vseconds,
|
||||
#'shorttimestr,
|
||||
#'shortvtimestr,
|
||||
#'shout,
|
||||
#'shutdown,
|
||||
#'sin,
|
||||
#'sizeof,
|
||||
// #'slice_array,
|
||||
#'snoop,
|
||||
#'sort_array,
|
||||
#'space,
|
||||
#'sprintf,
|
||||
#'sqrt,
|
||||
#'sscanf,
|
||||
#'str2int,
|
||||
#'string_parser,
|
||||
#'stringp,
|
||||
#'strip,
|
||||
#'strlen,
|
||||
#'strstr,
|
||||
#'substr,
|
||||
// #'swap,
|
||||
#'symbol_function,
|
||||
#'symbol_variable,
|
||||
#'symbolp,
|
||||
#'sys_log,
|
||||
#'tail,
|
||||
#'tan,
|
||||
#'tell_object,
|
||||
#'tell_room,
|
||||
#'terminal_colour,
|
||||
#'test_bit,
|
||||
#'this_interactive,
|
||||
#'this_object,
|
||||
#'this_player,
|
||||
#'throw,
|
||||
#'time,
|
||||
#'time_to_vtime,
|
||||
#'timestr,
|
||||
#'to_array,
|
||||
#'to_float,
|
||||
#'to_int,
|
||||
#'to_object,
|
||||
#'to_string,
|
||||
#'touch,
|
||||
#'trace,
|
||||
#'traceprefix,
|
||||
#'transpose_array,
|
||||
#'trim,
|
||||
#'typeof,
|
||||
#'unbound_lambda,
|
||||
#'unique_array,
|
||||
#'unmkmapping,
|
||||
#'unshadow,
|
||||
#'upper_case,
|
||||
#'users,
|
||||
#'utime,
|
||||
#'vclock,
|
||||
#'vtime,
|
||||
#'vtime_to_time,
|
||||
#'vtimestr,
|
||||
#'walk_mapping,
|
||||
#'wem,
|
||||
#'wen,
|
||||
#'wer,
|
||||
#'wessen,
|
||||
#'widthof,
|
||||
#'wizardshellp,
|
||||
#'wizlist_info,
|
||||
#'wrap,
|
||||
#'wrap_say,
|
||||
#'write,
|
||||
#'write_bytes,
|
||||
#'write_file,
|
||||
#'xor_bits,
|
||||
#'xy2pol,
|
||||
|
||||
#',,
|
||||
#'=,
|
||||
#'+=,
|
||||
#'-=,
|
||||
#'&=,
|
||||
#'|=,
|
||||
#'^=,
|
||||
#'<<=,
|
||||
#'>>=,
|
||||
#'>>>=,
|
||||
#'*=,
|
||||
#'%=,
|
||||
#'/=,
|
||||
#'?,
|
||||
#'||,
|
||||
#'&&,
|
||||
#'|,
|
||||
#'^,
|
||||
#'&,
|
||||
#'==,
|
||||
#'!=,
|
||||
#'>,
|
||||
#'>=,
|
||||
#'<,
|
||||
#'<=,
|
||||
#'<<,
|
||||
#'>>,
|
||||
#'>>>,
|
||||
#'+,
|
||||
#'-,
|
||||
#'*,
|
||||
#'%,
|
||||
#'/,
|
||||
#'++,
|
||||
#'--,
|
||||
#'negate,
|
||||
#'!,
|
||||
#'~,
|
||||
#'({,
|
||||
#'([,
|
||||
#'[,
|
||||
#'[<,
|
||||
#'[..],
|
||||
#'[..<],
|
||||
#'[<..],
|
||||
#'[<..<],
|
||||
#'[..,
|
||||
#'[<..,
|
||||
#'({,
|
||||
#'([,
|
||||
}) ),
|
||||
|
||||
( values =
|
||||
({
|
||||
/* --- Integers: --- */
|
||||
0,
|
||||
1,
|
||||
-1,
|
||||
32,
|
||||
-32,
|
||||
40,
|
||||
-40,
|
||||
29292929,
|
||||
-5050211,
|
||||
__INT_MAX__,
|
||||
__INT_MIN__,
|
||||
|
||||
/* --- Floats: --- */
|
||||
0.0,
|
||||
0.5,
|
||||
-0.5,
|
||||
55.5,
|
||||
-55.5,
|
||||
999999999999999999999999999999999999999999999.99,
|
||||
-999999999999999999999999999999999999999999999.99,
|
||||
|
||||
/* --- Strings: --- */
|
||||
"",
|
||||
"foo bar",
|
||||
"%d %q %T",
|
||||
"0",
|
||||
"",
|
||||
" ",
|
||||
"_",
|
||||
"^^^^^^",
|
||||
"#^# #^#",
|
||||
" ^",
|
||||
"^ ",
|
||||
" - - - - ",
|
||||
"? ? ? ? ? ? ????? ???? ??",
|
||||
"°°°°°°°°°°°°°°°°°°°°°",
|
||||
"\\/ "*32,
|
||||
" !"*42,
|
||||
|
||||
/* --- Objekte: --- */
|
||||
touch("/obj/fackel"),
|
||||
touch("/obj/rucksack"),
|
||||
touch("/obj/rope"),
|
||||
touch("/secure/master"),
|
||||
clone_object("/obj/schiff"),
|
||||
clone_object("/obj/player"),
|
||||
clone_object("/obj/tisch"),
|
||||
|
||||
/* --- Closures: --- */
|
||||
(: :),
|
||||
(: (: 1 :) :),
|
||||
#'sizeof,
|
||||
#'garbage_collection,
|
||||
symbol_function("query_long", touch("/i/item")),
|
||||
lambda( ({'x, 'y}), ({#'?, ({#'>, 'x, 'y}), 'x, 'y}) ),
|
||||
unbound_lambda( ({'x}), ({#'==, 0, 'x}) ),
|
||||
|
||||
/* --- Arrays: --- */
|
||||
({ }),
|
||||
({ 0 }),
|
||||
({ "" }),
|
||||
({ ({ }) }),
|
||||
({ ([ ]) }),
|
||||
allocate(3000),
|
||||
|
||||
/* --- Mappings: --- */
|
||||
([ ]),
|
||||
([ (: :) ]),
|
||||
m_allocate(5,5),
|
||||
mkmapping(allocate(30), allocate(30, ({})), allocate(30, (:1:))),
|
||||
|
||||
}) )
|
||||
|
||||
); // catch
|
||||
|
||||
if(pointerp(values)) {
|
||||
values += ({0,0,0});
|
||||
|
||||
apply((: values[<3] = $1 :), &execute);
|
||||
apply((: values[<2] = $1 :), &values);
|
||||
apply((: values[<1] = $1 :), &efuns);
|
||||
}
|
||||
while(remove_call_out("execute_file") != -1);
|
||||
while(remove_call_out("do_replay") != -1);
|
||||
while(remove_call_out("do_record") != -1);
|
||||
|
||||
seteuid(getuid());
|
||||
}
|
||||
|
||||
int execute_file(string file)
|
||||
{
|
||||
int line;
|
||||
string str;
|
||||
mixed restore;
|
||||
|
||||
if(!stringp(file) || file_size(file) <= 0)
|
||||
{
|
||||
DEBUG("ERROR: Cannot execute "+file+": Invalid file.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG("Executing: "+file);
|
||||
|
||||
for(line = 0; (str=read_file(file, line, 2)) && strlen(str); line += 2)
|
||||
{
|
||||
restore = restore_value(str);
|
||||
|
||||
rm("/save/crash/LAST_EXEC");
|
||||
write_file("/save/crash/LAST_EXEC",
|
||||
save_value( ({file, line}) ));
|
||||
|
||||
#ifdef VERBOSE
|
||||
debug_message("File: "+file+" Line: "+line+"\n");
|
||||
#endif
|
||||
debug_message(sprintf("REPLAY: %O %O -> %O %O\n", restore[0], restore[1], efuns[ restore[0] ], map( restore[1], (: values[$1] :) )));
|
||||
|
||||
catch(
|
||||
apply( efuns[ restore[0] ],
|
||||
map( restore[1], (: values[$1] :) ) )
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
mixed query_values() { return values; }
|
||||
|
||||
int generate_file(string file)
|
||||
{
|
||||
int i, h, efun_index, * value_index;
|
||||
|
||||
if(!stringp(file) || !write_file(file, ""))
|
||||
{
|
||||
DEBUG("ERROR: Cannot write file: "+file);
|
||||
debug_message(wrap("ERROR: Cannot write file: "+file));
|
||||
|
||||
seteuid(getuid());
|
||||
|
||||
record("/save/crash/"+(mixed2str(utime())-"({,})"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG("Recording: "+file);
|
||||
|
||||
for(i = ITERATIONS; i--; )
|
||||
{
|
||||
efun_index = random(sizeof(efuns));
|
||||
value_index = ({});
|
||||
|
||||
for(h = random(MAX_ARGS+1); h--; )
|
||||
{
|
||||
value_index += ({ random(sizeof(values)) });
|
||||
}
|
||||
|
||||
write_file(file, save_value( ({efun_index, value_index}) ));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void replay(string file)
|
||||
{
|
||||
if (!file)
|
||||
{
|
||||
file = names[0];
|
||||
names = names[1..];
|
||||
}
|
||||
DEBUG("Stopping all actions and starting REPLAY for: "+file);
|
||||
|
||||
reset_all();
|
||||
|
||||
execute = ({ #'call_out, "do_replay", DELAY, file, 1 });
|
||||
|
||||
// Um this_player etc. loszuwerden einen Reset-Hack ;o)
|
||||
set_next_reset(DELAY);
|
||||
}
|
||||
|
||||
static void do_replay(string file, int number)
|
||||
{
|
||||
if(execute_file(file + right(number, 5, "_0000")))
|
||||
{
|
||||
call_out("do_replay", DELAY, file, number+1);
|
||||
}
|
||||
else call_out("replay", DELAY, 0);
|
||||
}
|
||||
|
||||
void record(string file)
|
||||
{
|
||||
DEBUG("Stopping all actions and starting RECORD for: "+file);
|
||||
|
||||
reset_all();
|
||||
|
||||
execute = ({ #'call_out, "do_record", DELAY, file, 1 });
|
||||
|
||||
// Um this_player etc. loszuwerden einen Reset-Hack ;o)
|
||||
set_next_reset(DELAY);
|
||||
}
|
||||
|
||||
static void do_record(string file, int number)
|
||||
{
|
||||
if(generate_file(file+right(number, 5, "_0000")))
|
||||
{
|
||||
call_out("execute_file", DELAY, file+right(number, 5, "_0000"));
|
||||
call_out("do_record", DELAY*2, file, number+1);
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
// Um this_player etc. loszuwerden einen Reset-Hack ;o)
|
||||
if(execute)
|
||||
{
|
||||
apply(execute[0], execute[1..]);
|
||||
execute = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void debug_query(string file, int line)
|
||||
{
|
||||
mixed restore;
|
||||
|
||||
restore = restore_value(read_file(file, line, 2));
|
||||
|
||||
rm("/save/crash/TEMP");
|
||||
write_file("/save/crash/TEMP",
|
||||
sprintf("apply( %Q, %Q )", efuns[ restore[0] ],
|
||||
map(restore[1], (: values[$1] :))));
|
||||
|
||||
({this_player()})->more("/save/crash/TEMP");
|
||||
}
|
||||
|
||||
void debug_exec(string file, int line)
|
||||
{
|
||||
mixed restore;
|
||||
|
||||
restore = restore_value(read_file(file, line, 2));
|
||||
|
||||
catch(
|
||||
apply( efuns[ restore[0] ], map(restore[1], (: values[$1] :)))
|
||||
);
|
||||
}
|
||||
|
||||
void create()
|
||||
{
|
||||
string str;
|
||||
mixed strs;
|
||||
|
||||
reset_all();
|
||||
|
||||
str = read_file("/save/crash/LAST_EXEC");
|
||||
|
||||
if(str)
|
||||
{
|
||||
catch( apply( #'debug_query, restore_value(str) ),
|
||||
write_file("/save/crash/CRASHERS",
|
||||
"-"*80 + "\n"
|
||||
+ read_file("/save/crash/TEMP")+ "\n" ) );
|
||||
}
|
||||
|
||||
#if 0
|
||||
strs = get_dir("/save/crash/1*");
|
||||
|
||||
foreach(str : strs)
|
||||
{
|
||||
rm("/save/crash/"+str);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
call_out("record", 4, "/save/crash/"+(mixed2str(utime())-"({,})"));
|
||||
#else
|
||||
names = ({
|
||||
"/save/crash/crash1"
|
||||
});
|
||||
call_out("replay", 4, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- End of file. --- */
|
686
mudlib/uni-crasher/crashleak.c
Normal file
686
mudlib/uni-crasher/crashleak.c
Normal file
|
@ -0,0 +1,686 @@
|
|||
// This is for crash purposes only. Don't run it in a production MUD.
|
||||
//
|
||||
// It may still depend on some UNItopia stuff, I haven't tested it with other
|
||||
// libs. If you're using the UNItopia Mudlib to run it, you have to remove all
|
||||
// nomask simul efuns (empty the file /secure/simul_efun/secure.inc), and
|
||||
// unlock all privilege violations in /secure/master/compiler_control.inc by
|
||||
// adding return 1; of the function.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
// File: crashleak.c
|
||||
// Description: Try to crash the driver and/or find memory leaks
|
||||
// by calling EFuns and Operators with random arguments.
|
||||
// Based on my old crasher.c
|
||||
// Author: Menaures@UNItopia (2004-07-17)
|
||||
//
|
||||
|
||||
/* --- Documentation: --- */
|
||||
|
||||
/* --- Inherits: --- */
|
||||
|
||||
/* --- Includes: --- */
|
||||
#include <rtlimits.h>
|
||||
|
||||
// Replace this with some kind of output if you
|
||||
// want Debug-Messages
|
||||
#define DEBUG(x) {}
|
||||
|
||||
/* --- Defines: --- */
|
||||
|
||||
// Undef the following if you're not interested in Memleaks
|
||||
#define FIND_MEMORY_LEAKS
|
||||
|
||||
// Where shall we write our data to?
|
||||
#define CRASHLEAK_DIR "/save/crashleak/"
|
||||
|
||||
// Where is the doc/efun directory of the driver package?
|
||||
#define DOC_EFUN_DIR CRASHLEAK_DIR"doc/efun/"
|
||||
|
||||
#define FILE(x,y) (CRASHLEAK_DIR+l_time+"_"+sprintf("%'0'6d_%s", (y), (x)))
|
||||
#define GC_FILE(x) FILE("GC_"+(x), ++filecounter)
|
||||
#define RECORD_FILE(x) FILE("REC_"+(x), ++filecounter)
|
||||
#define LEAK_FILE(x) FILE("LEAK_"+(x), ++filecounter)
|
||||
#define LOG_FILE(x) FILE("LOG_"+(x), ++filecounter)
|
||||
|
||||
// How many calls shall we do per step?
|
||||
#define CALLS_PER_STEP 1000
|
||||
|
||||
// How long to wait between steps?
|
||||
// Careful, Memleak detection might not work for lower values!
|
||||
#define STEP_PAUSE 4
|
||||
|
||||
// Sometimes objects get removed out of the values array.
|
||||
// Do you want to reinitialize it every X steps?
|
||||
// For maximum Memleak Find reliability, set to 1,
|
||||
// which causes reinitialization in every step (halfing
|
||||
// the speed)
|
||||
#define REINIT_EVERY_N_STEPS 10
|
||||
|
||||
// This defines minimum and maximum number of arguments per
|
||||
// function call. Recorded files may still be executed with
|
||||
// old values if you change this.
|
||||
#define MIN_PARAMS 0
|
||||
#define MAX_PARAMS 15
|
||||
|
||||
// NOTE:
|
||||
// When looking for Memleaks, only one step per PAUSE will be made.
|
||||
// Thus, detecting all Memleaks of one real step will require
|
||||
// a minimum of CALLS_PER_STEP*STEP_PAUSE time until the next step
|
||||
// is done with full stress speed again. This is probably a long
|
||||
// time, however: if there are few leaks, lower CALLS_PER_STEP
|
||||
// will only add up to the time it takes to find one in the first
|
||||
// place...
|
||||
|
||||
/* --- Global Variables: --- */
|
||||
|
||||
int l_time = time(); // Just as a unique number...
|
||||
mixed * efun; // EFun- and Operator-Closures. Either #'foo or ({#'foo, min_param, max_param})
|
||||
mixed * value; // Value-set which contains all Data Types.
|
||||
int stepcounter; // For reinit after N steps.
|
||||
int filecounter; // For file naming.
|
||||
mixed * queue; // Queue, to have one call-out-loop instead of many
|
||||
#ifdef FIND_MEMORY_LEAKS
|
||||
mixed * leakage; // To track GCs and Execs for Leak detection.
|
||||
#endif
|
||||
|
||||
/* --- Prototypes: --- */
|
||||
|
||||
void crash(string file, closure callback);
|
||||
void leak(closure callback);
|
||||
|
||||
#ifdef FIND_MEMORY_LEAKS
|
||||
void check_for_leak(string file, mixed * exec);
|
||||
void step_by_step(string gc_file, string file, mixed * exec);
|
||||
#endif
|
||||
|
||||
/* --- Functions: --- */
|
||||
|
||||
/* --- Queue --- */
|
||||
|
||||
// Basic Queue, mainly to prevent recursion problems.
|
||||
// And to make call_out loops easier (we have more than one)
|
||||
|
||||
mixed * query_queue() { return queue; }
|
||||
|
||||
int push(int pos, varargs mixed * what)
|
||||
{
|
||||
if(!pointerp(queue))
|
||||
{
|
||||
queue = ({});
|
||||
}
|
||||
|
||||
if(pos <= 0)
|
||||
{
|
||||
pos = sizeof(queue) + 1;
|
||||
}
|
||||
|
||||
queue = queue[0..pos-2] + ({ what }) + queue[pos-1..];
|
||||
}
|
||||
|
||||
int pop()
|
||||
{
|
||||
mixed q;
|
||||
|
||||
if(pointerp(queue) && sizeof(queue))
|
||||
{
|
||||
q = queue[0];
|
||||
queue = queue[1..];
|
||||
apply(q[0],q[1..]);
|
||||
return sizeof(queue);
|
||||
}
|
||||
}
|
||||
|
||||
void step()
|
||||
{
|
||||
if(set_next_reset(0) > 300)
|
||||
{
|
||||
set_next_reset(150);
|
||||
}
|
||||
|
||||
pop();
|
||||
call_out(#'step, STEP_PAUSE);
|
||||
}
|
||||
|
||||
/* --- Crashleak Initialization: --- */
|
||||
|
||||
// Just to provide some LFun Closures below...
|
||||
string foo() { return "foo"; }
|
||||
mixed bar(mixed x, mixed y, mixed z) { return ({z,y,x}); }
|
||||
|
||||
mixed query_efun() { return efun; }
|
||||
|
||||
void init_efun()
|
||||
{
|
||||
DEBUG("init_efun()");
|
||||
// Generate list of all EFuns. /doc/efun/ is part of the driver package.
|
||||
// If it isn't part of your mudlib directory, copy it somewhere in it
|
||||
// and modify the path accordingly.
|
||||
string * list = get_dir(DOC_EFUN_DIR"*") - ({".","..","[]"});
|
||||
|
||||
// Convert them to EFun closures using a restore_value hack.
|
||||
|
||||
efun = restore_value("#1:0\n({#e:"+implode(list, ",#e:")+",})\n");
|
||||
|
||||
// Kill unrecognized and dangerous EFuns.
|
||||
efun -= ({0,
|
||||
#'efun::set_driver_hook, // it makes the crasher stop running
|
||||
#'efun::limited, // too much fun
|
||||
#'efun::set_this_object, // poses problems
|
||||
#'efun::garbage_collection, // Can't find no leaks otherwise
|
||||
#'efun::shutdown, // Can't find no crashes otherwise
|
||||
#'efun::set_limits}); // Messes things up naturally
|
||||
|
||||
// Add Operator closures. Have not found a way to generate this list
|
||||
// automatically yet, so you might want to check if it's still up2date.
|
||||
// See lex.c ~ approx line 1000 for a list (this one's of 2004/07/17).
|
||||
efun +=
|
||||
({ #'+= ,#'++ ,#'+ ,#'-= ,#'-- ,#'- ,#'*= ,#'* ,#'/=
|
||||
,#'/ ,#'%= ,#'% ,#', ,#'^= ,#'^ ,#'|| ,#'||= ,#'|=
|
||||
,#'| ,#'&& ,#'&&= ,#'&= ,#'& ,#'~ ,#'<= ,#'<<= ,#'<<
|
||||
,#'< ,#'>= ,#'>>= ,#'>>>= ,#'>>> ,#'>> ,#'> ,#'== ,#'=
|
||||
,#'!= ,#'! ,#'?! ,#'? ,#'[..] ,#'[..<] ,#'[<..]
|
||||
,#'[<..<] ,#'[..>] ,#'[>..] ,#'[<..>]
|
||||
,#'[>..<] ,#'[>..>] ,#'[.. ,#'[<..
|
||||
,#'[>.. ,#'[,] ,#'[ ,#'[< ,#'[>
|
||||
,#'({ ,#'([ ,#'-> ,#'(<
|
||||
});
|
||||
}
|
||||
|
||||
mixed query_values() { return value; }
|
||||
|
||||
struct Bar {
|
||||
mixed four;
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
int one, *two;
|
||||
struct Bar three;
|
||||
};
|
||||
|
||||
void init_value()
|
||||
{
|
||||
DEBUG("init_value()");
|
||||
|
||||
// The more values, the more variation, the better.
|
||||
// Feel free to add stuff to this list. However, don't modify it
|
||||
// on the fly, changing this array will make recorded files useless.
|
||||
|
||||
// Please refrain from using self-referencing structures unless you
|
||||
// want to test the crash aspect only. Include self-referencing
|
||||
// stuff inside #ifndef FIND_MEMORY_LEAKS #endif blocks only.
|
||||
|
||||
if(pointerp(value))
|
||||
{
|
||||
// Do some cleanup first:
|
||||
map(value, (: objectp($1) && destruct($1) :));
|
||||
}
|
||||
|
||||
value = 0;
|
||||
value =
|
||||
({
|
||||
/* --- Integer: --- */
|
||||
-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
|
||||
-1000,1000,-50000,50000,-2000000,2000000,
|
||||
__INT_MIN__+16,__INT_MAX__-16,__INT_MIN__,__INT_MAX__,
|
||||
|
||||
/* --- Float: --- */
|
||||
0.0,0.001,-0.001,-0.5,0.5,0.99,-0.99,1.01,-1.01,
|
||||
42.767,-42.767,1.0,2.0,3.0,-1.0,-2.0,-3.0,
|
||||
to_float(__INT_MIN__), to_float(__INT_MAX__),
|
||||
1.0e+100, -1.0e+100,
|
||||
|
||||
/* --- String: --- */
|
||||
"", " ", " ", "!_!_", "_!_!",
|
||||
"foo","bar","foo bar", "%d", "%Q", "0", "^^^^^^",
|
||||
"#^# #^#", " ^",
|
||||
"^ ", " - - - - ",
|
||||
"? ? ? ? ? ? ????? ???? ??", "",
|
||||
"\\/ "*32, " !"*42, "/", "/..",
|
||||
"/a", "/d/", "/w/..",
|
||||
"%#Q%#Q%#Q","%d%-=80s%%",
|
||||
save_value(efun), save_object(),
|
||||
|
||||
/* --- Object: --- */
|
||||
|
||||
// This is mudlib specific, please provide some objects;
|
||||
// Preferred are Blueprints, Clones, Objects with Environment,
|
||||
// and Objects which have other objects inside (rooms).
|
||||
//
|
||||
// Note that random calls (for example to destruct()) might
|
||||
// remove objects; so they should be reloaded here.
|
||||
// A proper cleanup of old objects then would probably be good too.
|
||||
load_object("/obj/fackel"), clone_object("/obj/fackel"),
|
||||
load_object("/obj/player"), clone_object("/obj/player"),
|
||||
load_object("/i/item/message"),
|
||||
clone_object("/obj/rucksack"), clone_object("/obj/kurstafel"),
|
||||
clone_object("/obj/wizard_shell"), clone_object("/secure/obj/login"),
|
||||
load_object("/secure/obj/login"), load_object("/apps/error_db"),
|
||||
load_object("/apps/plugin"), clone_object("/obj/zauberstab"),
|
||||
load_object("/room/church"), load_object("/room/void"),
|
||||
load_object("/room/hell"), load_object("/room/death/death"),
|
||||
load_object("/room/rathaus/treppe"),
|
||||
load_object("/room/rathaus/konferenz"),
|
||||
load_object("/room/rathaus/forum"),
|
||||
clone_object("/obj/monster"), clone_object("/obj/monster"),
|
||||
clone_object("/obj/monster"), clone_object("/obj/monster"),
|
||||
|
||||
/* --- Closure: --- */
|
||||
(: :), (: 1 :), (: 0 :), (: $2/$1 :),
|
||||
#'efun::max, #'efun::input_to, #'efun::this_player,
|
||||
#'efun::this_object, #'efun::call_out,
|
||||
symbol_function("query_long", load_object("/i/item")),
|
||||
symbol_function("query_real_name", load_object("/i/player/player")),
|
||||
#'foo, #'bar,
|
||||
function { return 2 * $1; },
|
||||
function int (int a) { return 2 * a; },
|
||||
function (int a) { return 2 * a; },
|
||||
lambda( ({'x, 'y}), ({#'?, ({#'>, 'x, 'y}), 'x, 'y}) ),
|
||||
unbound_lambda( ({'x}), ({#'==, 0, 'x}) ),
|
||||
(: for(;;); :), (: while($1); :),
|
||||
|
||||
/* --- Array: --- */
|
||||
({}), ({ ({}) }), ({ (: :) }), ({ 0 }), ({ 1 }),
|
||||
({ "" }), ({ ([]) }), ({#'efun::min}),
|
||||
allocate(5), allocate(10,1), allocate(query_limits(1)[LIMIT_ARRAY]),
|
||||
({'x, 'y}), ({#'?, ({#'>, 'x, 'y}), 'x, 'y}),
|
||||
({'x}), ({#'==, 0, 'x}),
|
||||
|
||||
/* --- Mapping: --- */
|
||||
([:0]), ([:1]), ([:2]), (["a":"b"]),([([1]):({2,3})]),
|
||||
mkmapping( ({1,2,3,4,5,6,7,8,9,10}), ({1,2,3,4,5,6,7,8,9,10}) ),
|
||||
mkmapping( ({"1","2","3","4","5","6","7","8","9","10"}) ),
|
||||
([ load_object("/apps/groups") ]),
|
||||
([ #'efun::allocate ]),
|
||||
|
||||
/* --- Symbol / Quoted: --- */
|
||||
'a, 'b, 'c, quote(allocate(10)),
|
||||
'dont_know_what_this_is_supposed_to_be_it_sure_is_fun,
|
||||
'whatever_floats_your_boat,
|
||||
|
||||
/* --- Struct: --- */
|
||||
});
|
||||
|
||||
// --- Lets add some special values. ---
|
||||
|
||||
// Container inside Container inside...
|
||||
object ob = clone_object("/obj/rucksack");
|
||||
|
||||
|
||||
for(int i = 10; i--; )
|
||||
{
|
||||
object ob2 = clone_object("/obj/rucksack");
|
||||
ob->move(ob2);
|
||||
ob=ob2;
|
||||
}
|
||||
|
||||
value += ({ob});
|
||||
|
||||
// Some random strings. Good for crashing, bad for debugging...
|
||||
// So to make things reproducible, we generate them only once,
|
||||
// and only load them afterwards. Delete the Savefile if you
|
||||
// want new random strings.
|
||||
|
||||
string str;
|
||||
|
||||
if(str = read_file(CRASHLEAK_DIR"random_strings.o"))
|
||||
{
|
||||
value += restore_value(str);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
string * random_strings = ({});
|
||||
|
||||
for(int i = 10; i--; )
|
||||
{
|
||||
int * arr;
|
||||
|
||||
arr = map(allocate(random(100)), (: random(256) :));
|
||||
random_strings += ({ to_string(arr) });
|
||||
}
|
||||
|
||||
// Save these strings so that we can reuse them next time.
|
||||
write_file(CRASHLEAK_DIR"random_strings.o",
|
||||
save_value(random_strings));
|
||||
|
||||
// Don't forget to add them to the values array...
|
||||
value += random_strings;
|
||||
}
|
||||
|
||||
// Structs
|
||||
struct Bar foo = (<Bar> 10);
|
||||
struct Foo bar = (<Foo> 1, ({"2",3}), (<Bar> 5));
|
||||
|
||||
value += ({foo,bar})*20;
|
||||
}
|
||||
|
||||
mixed do_plot_efun(closure cl)
|
||||
{
|
||||
// DEBUG(sprintf("do_plot_efun(%#Q)",cl));
|
||||
|
||||
object ob = this_object();
|
||||
|
||||
int min_p = MIN_PARAMS;
|
||||
int max_p = MAX_PARAMS;
|
||||
|
||||
for(int p = MAX_PARAMS; p >= MIN_PARAMS; p--)
|
||||
{
|
||||
|
||||
|
||||
string str = catch(apply(cl, allocate(p)); nolog);
|
||||
|
||||
// DEBUG(sprintf(" str -> %#Q", str));
|
||||
|
||||
if(str && strstr(str, "many arguments") != -1)
|
||||
{
|
||||
max_p--;
|
||||
}
|
||||
|
||||
else if(str && strstr(str, "few arguments") != -1)
|
||||
{
|
||||
min_p++;
|
||||
}
|
||||
}
|
||||
|
||||
set_this_object(ob);
|
||||
seteuid(0);
|
||||
seteuid(getuid());
|
||||
|
||||
if(min_p != MIN_PARAMS || max_p != MAX_PARAMS)
|
||||
{
|
||||
return ({cl, min_p, max_p});
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
void plot_efun()
|
||||
{
|
||||
DEBUG("plot_efun()");
|
||||
|
||||
efun = filter(efun, #'closurep);
|
||||
efun = limited(#'map, ({10000000}), efun, #'do_plot_efun);
|
||||
|
||||
garbage_collection(GC_FILE("plot_efun"));
|
||||
}
|
||||
|
||||
void init_crashleak(closure callback)
|
||||
{
|
||||
DEBUG("init_crashleak()");
|
||||
|
||||
// Sometimes init fails. Recall.
|
||||
push(1, #'init_crashleak, callback);
|
||||
|
||||
string str;
|
||||
|
||||
if(str = catch(limited(#'init_efun, ({1000000})); publish))
|
||||
{
|
||||
debug_message("CRASHLEAK: init_efun failed:\n"+str+"\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(str = catch(limited(#'init_value, ({1000000})); publish))
|
||||
{
|
||||
debug_message("CRASHLEAK: init_value failed:\n"+str+"\n");
|
||||
}
|
||||
|
||||
garbage_collection(GC_FILE("AFTER_INIT"));
|
||||
|
||||
// Del the old entry
|
||||
queue = queue[1..];
|
||||
push(0, callback);
|
||||
|
||||
// Determine EFun parameter counts next step.
|
||||
push(1, #'plot_efun);
|
||||
}
|
||||
|
||||
void crashleak()
|
||||
{
|
||||
DEBUG("crashleak()");
|
||||
|
||||
if(stepcounter++ == REINIT_EVERY_N_STEPS)
|
||||
{
|
||||
init_crashleak(#'crashleak);
|
||||
stepcounter=0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FIND_MEMORY_LEAKS
|
||||
push(0, #'crash, RECORD_FILE("cl"), #'check_for_leak);
|
||||
#else
|
||||
push(0, #'crash, RECORD_FILE("cl"), #'crashleak);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Crash Execution: --- */
|
||||
|
||||
mixed * pick()
|
||||
{
|
||||
DEBUG("pick()");
|
||||
|
||||
mixed * erg = ({});
|
||||
|
||||
int f, p;
|
||||
|
||||
for(int i = CALLS_PER_STEP; i--; )
|
||||
{
|
||||
f = random(sizeof(efun));
|
||||
|
||||
if(closurep(efun[f]))
|
||||
{
|
||||
p = MIN_PARAMS + random(MAX_PARAMS-MIN_PARAMS);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
p = efun[f][1] + random(efun[f][2]-efun[f][1]);
|
||||
}
|
||||
|
||||
|
||||
erg +=
|
||||
({
|
||||
// Pick EFun index.
|
||||
({ random(sizeof(efun)),
|
||||
// Pick p parameter indices.
|
||||
map(allocate(p), (: random(sizeof(value)) :)),
|
||||
// Will be replaced with a string later:
|
||||
// (debugmessage of what was executed)
|
||||
0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return erg;
|
||||
}
|
||||
|
||||
varargs void exec(mixed * exec, int quiet)
|
||||
{
|
||||
DEBUG("exec()");
|
||||
|
||||
string file;
|
||||
string text = "";
|
||||
object ob = this_object();
|
||||
|
||||
debug_message("start_of_exec\n");
|
||||
|
||||
foreach(mixed * x : exec)
|
||||
{
|
||||
mixed f = efun[x[0]];
|
||||
if(pointerp(f)) f=f[0];
|
||||
mixed * v = map(x[1], (: value[$1] :));
|
||||
string str = sprintf("%d %#Q\n", x[0],x[1]);
|
||||
|
||||
// Note: This chance affects arrays by reference. :-)
|
||||
x[2] = str;
|
||||
|
||||
debug_message(sprintf("exec: %s",str));
|
||||
|
||||
set_this_object(ob);
|
||||
seteuid(0);
|
||||
seteuid(getuid());
|
||||
catch(apply(f, v); reserve (max(get_eval_cost()/2,100000)), nolog);
|
||||
|
||||
if(get_eval_cost() < 100000)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_this_object(ob);
|
||||
|
||||
debug_message("end_of_exec\n");;
|
||||
}
|
||||
|
||||
void crash(string file, closure callback)
|
||||
{
|
||||
DEBUG("crash()");
|
||||
|
||||
mixed * exec;
|
||||
|
||||
/* --- Pick what we will execute in this run: --- */
|
||||
exec = limited(#'pick, ({1000000}));
|
||||
|
||||
/* --- Record it to the file. --- */
|
||||
write_file(file, save_value(exec));
|
||||
|
||||
/* --- Execute it. --- */
|
||||
limited(#'exec, ({1000000}), exec);
|
||||
|
||||
funcall(callback, file, exec);
|
||||
}
|
||||
|
||||
/* --- Leak detection: --- */
|
||||
|
||||
int analyze(string gc_file)
|
||||
{
|
||||
DEBUG("analyze("+gc_file+")");
|
||||
|
||||
string s = read_file(gc_file);
|
||||
|
||||
if(!stringp(s))
|
||||
{
|
||||
debug_message(sprintf("CRASHLEAK: Could not read file %#Q (%#Q)!\n",gc_file,s));
|
||||
return 0;
|
||||
}
|
||||
|
||||
string * str = explode(s, "\n");
|
||||
|
||||
return sizeof(regexp(str, "freeing.*block"));
|
||||
}
|
||||
|
||||
void leak_gc(string file, mixed * exec)
|
||||
{
|
||||
DEBUG("leak_gc( ["+sizeof(exec)+"] )");
|
||||
|
||||
string sbs = GC_FILE("sbs");
|
||||
|
||||
// GC.
|
||||
garbage_collection(sbs);
|
||||
// Note this file will be created later.
|
||||
|
||||
// Push.
|
||||
push(1, #'step_by_step, sbs, file, exec);
|
||||
|
||||
// Execute.
|
||||
limited(#'exec, ({1000000}), exec, 1);
|
||||
}
|
||||
|
||||
void step_by_step(string gc_file, string file, mixed * exec)
|
||||
{
|
||||
DEBUG("step_by_step()");
|
||||
|
||||
// Okay. Binary search.
|
||||
|
||||
// Was there a leak?
|
||||
if(analyze(gc_file))
|
||||
{
|
||||
// Whee! There was one. Let's see what we do.
|
||||
|
||||
// How many execs are there which might have caused the leak?
|
||||
if(sizeof(exec) == 1)
|
||||
{
|
||||
// Only one? Okay, this is it then.
|
||||
DEBUG("LEAK: "+exec[0][2]+"\n");
|
||||
write_file(LEAK_FILE(explode(gc_file,"/")[<1]), exec[0][2]+"\n");
|
||||
|
||||
// We haven't done a GC, so we can pop:
|
||||
call_out(#'pop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Okay. Do the first half now...
|
||||
leak_gc(file, exec[..(sizeof(exec)/2)-1]);
|
||||
// ...push the second half into the first queue, coz we can't do
|
||||
// to garbage_collection() at once.
|
||||
push(1, #'leak_gc, file, exec[(sizeof(exec)/2)..]);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// We haven't done a GC, so we can pop:
|
||||
call_out(#'pop, 0);
|
||||
}
|
||||
|
||||
// And wait...
|
||||
}
|
||||
|
||||
void check_for_leak(string file, mixed * exec)
|
||||
{
|
||||
DEBUG("check_for_leak()");
|
||||
|
||||
string gc_file = GC_FILE("check_for_leak");
|
||||
|
||||
// Warning: This is actually executed at the end of the cycle,
|
||||
// and not right now.
|
||||
garbage_collection(gc_file);
|
||||
// This means gc_file does not exist now yet.
|
||||
|
||||
// Check previous leakage (their gc_file exists now)
|
||||
if(leakage && analyze(leakage[0]))
|
||||
{
|
||||
// We need to do a step by step further investigation
|
||||
// of this exec to find which call exactly has caused
|
||||
// the leak.
|
||||
push(0, #'step_by_step, leakage[0], leakage[1], leakage[2]);
|
||||
|
||||
// Continue Crashing afterwards.
|
||||
push(0, #'crashleak);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// nothing to do. continue crashing.
|
||||
crashleak();
|
||||
}
|
||||
|
||||
// Remember this leakage and test it in the next run.
|
||||
leakage = ({gc_file,file,exec});
|
||||
}
|
||||
|
||||
/* --- Applied LFuns: --- */
|
||||
|
||||
void reset()
|
||||
{
|
||||
if(sizeof(queue) <= 0)
|
||||
{
|
||||
push(0, #'init_crashleak, #'crashleak);
|
||||
}
|
||||
|
||||
if(find_call_out(#'step) <= 0)
|
||||
{
|
||||
call_out(#'step, STEP_PAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
void create()
|
||||
{
|
||||
DEBUG("create()");
|
||||
|
||||
garbage_collection(GC_FILE("AFTER_CREATE"));
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/* --- End of file. --- */
|
152
mudlib/uni-crasher/secure.inc
Normal file
152
mudlib/uni-crasher/secure.inc
Normal file
|
@ -0,0 +1,152 @@
|
|||
// This file is part of UNItopia Mudlib.
|
||||
// ----------------------------------------------------------------
|
||||
// File: /secure/simul_efun/secure.inc
|
||||
// Description: Security Funktionen / Gesperrte Funktionen
|
||||
// Author: Freaky
|
||||
// Modified by: Freaky (31.03.1999) set_environment, object_info hinzugefuegt
|
||||
// Freaky (26.06.1999) command hinzugefuegt
|
||||
//
|
||||
// $Log: secure.inc,v $
|
||||
// Revision 1.1.1.1 2006/07/10 02:42:07 lynx
|
||||
// ldmud 3.3.714
|
||||
//
|
||||
// Revision 1.3 2001/01/30 23:59:01 sissi
|
||||
// Bergeweise CVS Log Eintraege eingetragen.
|
||||
// Hoffentlich nirgends doppelt und nirgends zu wenig.
|
||||
//
|
||||
|
||||
#pragma strict_types
|
||||
#pragma save_types
|
||||
|
||||
//
|
||||
// Dieser File ist der einizge Teil der Simul Efun mit
|
||||
// nomask simul_efun Privileg.
|
||||
// (siehe /secure/master/compiler_control::privilege_violation())
|
||||
//
|
||||
|
||||
/*
|
||||
* Nur der Shutdown-Daemon darf die efun shutdown verwenden!
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Gesperrte efuns
|
||||
*/
|
||||
#if __EFUN_DEFINED__(shutdown)
|
||||
nomask void shutdown() {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
#if __EFUN_DEFINED__(set_next_reset)
|
||||
nomask int set_next_reset(int delay) {}
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if __EFUN_DEFINED__(heart_beat_info)
|
||||
nomask object *heart_beat_info() {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(object_info)
|
||||
nomask mixed *object_info(object ob, int what) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(debug_info)
|
||||
nomask varargs mixed debug_info(int flag, mixed m) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(move_object)
|
||||
nomask void move_object(object ob1, object ob2) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(set_this_player)
|
||||
nomask void set_this_player(object ob) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(set_environment)
|
||||
nomask void set_environment(object ob1, object ob2) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(efun308)
|
||||
nomask void efun308(object ob1, object ob2) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(swap)
|
||||
nomask void swap(object ob) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(break_point)
|
||||
nomask void break_point() {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(functionlist)
|
||||
nomask mixed *functionlist(mixed ob, int flag) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(query_actions)
|
||||
nomask mixed *query_actions(mixed ob, mixed flag) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(garbage_collection)
|
||||
nomask void garbage_collection() {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(command)
|
||||
nomask int command(string str) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(last_instructions)
|
||||
nomask varargs string *last_instructions(int len, int verbose) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(command_stack)
|
||||
nomask mixed *command_stack() {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(command_stack_depth)
|
||||
nomask int command_stack_depth() {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(set_buffer_size)
|
||||
nomask int set_buffer_size(int size) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
#if __EFUN_DEFINED__(restore_value)
|
||||
nomask mixed restore_value(string str) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(save_value)
|
||||
nomask string save_value(mixed m) {}
|
||||
#endif
|
||||
*/
|
||||
|
||||
/*
|
||||
#if __EFUN_DEFINED__(clones)
|
||||
nomask varargs object *clones(mixed m, int i) {}
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if __EFUN_DEFINED__(set_connection_charset)
|
||||
nomask void set_connection_charset(mixed a, int i) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(binary_message)
|
||||
nomask varargs int binary_message(mixed m, int i) {}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(query_ip_number)
|
||||
nomask varargs string query_ip_number(object who)
|
||||
{
|
||||
return "0.0.0.0";
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __EFUN_DEFINED__(query_ip_name)
|
||||
nomask varargs string query_ip_name(object who)
|
||||
{
|
||||
return "leider.nicht.mehr.verfuegbar";
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue