1
0
Fork 0
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:
PSYC 2009-03-03 04:27:01 +01:00
commit 2ede0de60e
278 changed files with 230984 additions and 0 deletions

14
mudlib/uni-crasher/README Normal file
View 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.

View 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. --- */

View 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. --- */

View 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