Code Monkey home page Code Monkey logo

fuzzball's Introduction

Fuzzball MUCK GNU/Linux Build Status Windows Build Status FreeBSD Build Status

Fuzzball is a MUCK server, an online text-based multi-user chat and roleplaying game. Multiple people may join, set up characters, talk, and interact, exploring and building a common world. Nearly every aspect of the game can be customized via MPI-driven descriptions and MUF programs.

Documentation

Fuzzball also offers a built-in help system. Connect, then type help for guidance.

Downloads

Building and Running from Source

Usage

For a comprehensive guide to running a muck, check out MINK - The Muck Information Kiosk.

If you only need a quick test environment, read the instructions for your operating system in Building and Running from Source right above.

Feedback

You can send bug reports, feature requests, or other general feedback to [email protected]

fuzzball's People

Contributors

aidanpb avatar charlesreiss avatar cyberleo avatar davidatpurdue avatar dbenoy avatar digitalcircuit avatar dinoex avatar foxbird avatar hyena avatar kyanha avatar loonesbury avatar revarbat avatar sizer99 avatar skylerbunny avatar syversed avatar tanabi avatar wolfwings avatar wyld-sw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fuzzball's Issues

lsedit is broken

lsedit me = test
<    Welcome to the list editor.  You can get help by entering '.h'     >
< '.end' will exit and save the list.  '.abort' will abort any changes. >
<    To save changes to the list, and continue editing, use '.save'     >
Program Error.  Your program just got the following error.
cmd-lsedit(#107), line 24; CALL: Program not compilable.
System stack backtrace:
  0) cmd-lsedit(#107) line 24, in lsedit-loop(:
 24:     EDITORloop
  1) cmd-lsedit(#107) line 89, in cmd-lsedit(:
 89: ;
*done*

cmd-lsedit is the version from here. all libs are installed from here.

TLS connections broken on latest build?

As of this date and time, I'm unable to connect to our testing server after pulling the latest code and performing a rebuild. The socket connects, but no welcome message is printed, and if I try to send any text (such as to log in), the connection immediately drops. Nothing out of the ordinary displayed in the logs. Unsecure connections continue to function normally. Let me know what additional data you need.

MUF code outside of any word should at least be a warning

In a MUF file one can have code outside of any word like:: x ; foreach repeat. (Not surprisingly, I've found some bugs in how this code is handled.) This code is unreachable but still part of the compiled program instruction list. Probably this should be an error (if we aren't concerned about this kind of backwards-compatibility) or a warning.

"Only programmers are allowed to @list."

I'm not sure if this was an intentional change. In many cases, publicly-usable programs have implementation instructions buried in the MUF body itself, which needs to be @listed to see, often by non-MUCKER users. This also goes directly against the documented functionality of the VIEWABLE flag, as shown here:

When VEHICLE is set on a program, it is called VIEWABLE, and enables the program to be @listed.

Same with @list documentation:

Lists lines in a program, provided you control it or it is VIEWABLE.

@version output from SPR, where this behavior was confirmed:

Version: Muck2.2fb7.00b1(3) Compiled on: Fri Feb 23 2018 at 01:38:34 UTC
Options: GODPRIV IPV6 MCP RESOLVER SSL

FB7 does not support MODP-based Diffie-Hellman

Testing has revealed that FB7 supports ECDH key agreement, but not traditional modulo-based DH key agreement. While ECDH is superior in many aspects, it's entirely possible (perhaps even likely) that some TLS v1.0-only clients support DH while lacking support for ECDH. Enabling this support might go a long way toward eventually being able to disable the (now deprecated/insecure) RSA encryption-based cipher modes.

Tested using tf5.0b8 on CentOS 7.

Configured a test MUCK using the following SSL preference:
aRSA+EECDH+AESGCM:aRSA+EDH+AESGCM:aRSA+EECDH+AES+SHA384:aRSA+EECDH+AES+SHA256:aRSA+EDH+AES+SHA384:aRSA+EDH+AES+SHA256:aRSA+EECDH+AES+SHA1:aRSA+EDH+AES+SHA1:aRSA+AESGCM:aRSA+AES+SHA384:aRSA+AES+SHA256:aRSA+AES+SHA1:!SRP:!PSK

$ openssl ciphers 'aRSA+EECDH+AESGCM:aRSA+EDH+AESGCM:aRSA+EECDH+AES+SHA384:aRSA+EECDH+AES+SHA256:aRSA+EDH+AES+SHA384:aRSA+EDH+AES+SHA256:aRSA+EECDH+AES+SHA1:aRSA+EDH+AES+SHA1:aRSA+AESGCM:aRSA+AES+SHA384:aRSA+AES+SHA256:aRSA+AES+SHA1:!SRP:!PSK' | tr ':' '\n'

ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-SHA384
ECDHE-RSA-AES128-SHA256
DHE-RSA-AES256-SHA256
DHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA
ECDHE-RSA-AES128-SHA
DHE-RSA-AES256-SHA
DHE-RSA-AES128-SHA
AES256-GCM-SHA384
AES128-GCM-SHA256
AES256-SHA256
AES128-SHA256
AES256-SHA
AES128-SHA

Attempting to connect to the test MUCK succeeds using the ECDHE-RSA-AES256-GCM-SHA384 cipher suite.

Appending !EECDH to the end of the cipher preferences string, restarting the MUCK, and reattempting the connection succeeds using the AES256-GCM-SHA384 cipher suite, which is the highest-preference (obsolete) RSA encryption mode specified in the cipher preferences.

Performing the same tests against a web server causes tf to connect to the web server using the DHE-RSA-AES256-GCM-SHA384 cipher suite, which is the legacy-but-still-secure MODP-based Diffie-Hellman key agreement mode.

MUF integer arithmetic operation implementations invoke undefined behavior

MUF arithmetic operations +, -, bitshift allow overflow/underflow to happen or bitshifts which are larger than the size of an integer. For + and -, they detect when this produces the wrong result and set the err_ibounds? flag. For bitshift, they do not. In all cases, the implementations will invoke undefined behavior.

For bitshift, the result in practice of shifting by more than the width of the integer type varies; sometimes the the result is 0 or -1 as expected, but sometimes the shift amount is truncated based on the maximum possible shift amount instead.

In the case of + and -, this usually works out to wrapping around in twos complement, which is probably the behavior we expect, but this is not guaranteed without something like the GCC flag -fwrapv.

Set up regression tests, include with continuous integration

Eventually, Fuzzball should have some form of automated tests that run locally, perhaps a separate make test step. Ideally, this would include testing normal and SSL connections, running the MUF regression set, and validating that at least basic commands work, if not all commands.

Travis CI and Appveyor could make use of these tests and make sure that new changes don't accidentally break old functionality.

This is a long-term issue, perhaps after the build system is unified, and should involve careful investigation of available testing frameworks (e.g. Google Test), or, if needed, writing one from scratch (e.g. Bitlbee's approach).

Futex wait causing MUCK-wide lockup

We're experiencing an issue, albeit infrequently, where the MUCK will completely stop responding to input. Attempting to trace the process yields the following:

# strace -p 22940
strace: Process 22940 attached
futex(0x7f6882b3bac0, FUTEX_WAIT_PRIVATE, 2, NULL

It hangs at this point until strace is interrupted. We've tried launching the MUCK with fbmuck compiled in debug mode, but it fails to read the database when compiled in such fashion. In the mean time, I've pulled down the latest code as of this date/time in the hopes that a committed change has resolved the issue.

Add SECURE_SYSVARS primitive

Library functions that manipulate the database (especially on behalf of lesser-privileged programs) require the following prologue in order to secure their sysvars from inappropriate actions that the invoker would not be able to perform:

"me" match me ! me @ location loc ! trig trigger !

This prologue takes 8 instructions (push a literal, MATCH, store-to-me, get-from-me, LOCATION, store-to-loc, TRIG, store-to-trigger). This means that library calls can be expensive in terms of instructions used, just to ensure that they are not misused.

SECURE_SYSVARS is a verb to set me @, loc @, and trigger @ to the correct values in one instruction.

MUF constant folding doesn't set err_ibounds?, etc.

Something like 2147483647 1 + can overflow without making err_ibounds? true when the optimize_muf @tune is set. This is because the constant folding performed in OptimizeIntermediate does not check for overflow.

various memory leaks and other errors found via fuzzing

Here are some memory leaks and buffer over/underflows from fuzz testing:

  • @tune oTest=here leaks at tune.c:810 (strdup into oldvalue)
  • @act toTest=here, then @lock toTest=#3& performs an out-of-bounds stack read (underflow) at boolexp.c:193 (parse_boolexp_F)
  • @find o[^x] on a database containing an object named "Two" performs an out-of-bounds access in smatch when performing smatch for o and o[^x]*
  • @act toTest=here then @fail toTest={&propdirs-example:r} then toTest will perform an out-of-bounds write to cmdbuf at msgparse.c line 770.
  • @act toTest=here then @fail toTest={le:rgo,\ then toTest will leak from the malloc at msgparse line 686 (for argv[argv]).
  • the MPI {list:,me} performs an out-of-bounds access at msgparse.c:250 (listname[len-1]); there appears to be a similar problem with {select:...} at msgparse.c:190
  • the MPI {NULL:{WHILE:1,{NULL:x}{NULL}{NULL:{NULL:{NULL}}}}}}}}}}}}}} leaks from msgparse.c line 903 (argv[i] = (char *) realloc(.... in the mfun_list[s].parsep case)
  • the MPI {filter:b,a,{in`valid}}}}} leaks from msgparse.c:686
  • the malformed MUF : main FOR IF BREAK leaks (when compiled) from add_loop_exit() around compile.c:3134
  • the MUF "" NEWPROGRAM performs a null pointer dereference
  • the MUF NEXTENTRANCE doesn't check for stack underflow
  • the MUF "" 0.0 0.0 0.0 DIFF3 when run on an empty stack triggers an assertion failure on a MUCK built with --enable-debug
  • the MUF program : x 0 forcedby_array array_notify_secure ; causes an assertion failure on a MUCK built with --enable-debug
  • the MUF program : main pop "" 0 over main and and ; causes an assertion failure on a MUCK built with --enable-debug

Resolver lockup during shutdown

When attempting to terminate the MUCK via a systemd unit, shutdown stalls while waiting for the resolver process to exit. Once a kill is sent to the resolver process, everything proceeds to shutdown correctly.

@version:
Version: Muck2.2fb7.00a2(2) Compiled on: Sun Dec 18 2016 at 14:18:39 UTC
Options: DETACH GODPRIV IPV6 MCP RESOLVER SSL
# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.1 LTS
Release:        16.04
Codename:       xenial
# uname -a
Linux tassmoj.sprmuck.org 4.4.0-53-generic #74-Ubuntu SMP Fri Dec 2 15:59:10 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
# cat /etc/systemd/system/fuzzball-spr.service

[Unit]
Description=Fuzzball MUCK Server (SPR)
After=network.target

[Service]
Type=forking
PIDFile=/opt/fuzzball/spr/game/fbmuck.pid
ExecStart=/opt/fuzzball/spr/restart
Restart=on-failure
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target

MUF primitive copyobj documentation is incomplete

copyobj's documentation claims that programs can only create one object per run, but this is only true for non-M3+ programs. It also neglects to mention that the copied object is created in the current player's possession rather than copying the original location.

Compiling with --enable-debug prevents loading existing DB

When attempting to enable debugging for fbmuck for research on issue #40, we found that we were unable to launch the MUCK with debugging enabled. Same database when compiled without --enable-debug launched without issue.

# cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.1 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.1 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
# uname -a
Linux tassmoj.sprmuck.org 4.4.0-53-generic #74-Ubuntu SMP Fri Dec 2 15:59:10 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
@version
Version: Muck2.2fb7.00a2(4) Compiled on: Mon Dec 19 2016 at 01:48:47 UTC
Options: DETACH GODPRIV IPV6 MCP RESOLVER SSL
# cat fbmuck.err
LOADING: /opt/fuzzball/spr/game/data/std-db.db
[debug] dequeue_prog(#171, 1) called from compile.c:1915
dequeue_prog: tqhead = (nil)
[debug] dequeue_prog: 0 instances of #171
[debug] dequeue_prog(#2385, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(3): about to muf_event_dequeue(#2385, 1)
[debug] dequeue_prog: 0 instances of #2385
[debug] dequeue_prog(#7335, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#7335, 1)
[debug] dequeue_prog: 0 instances of #7335
[debug] dequeue_prog(#9009, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#9009, 1)
[debug] dequeue_prog: 0 instances of #9009
[debug] dequeue_prog(#9680, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#9680, 1)
[debug] dequeue_prog: 0 instances of #9680
[debug] dequeue_prog(#11696, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#11696, 1)
[debug] dequeue_prog: 0 instances of #11696
[debug] dequeue_prog(#27249, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#27249, 1)
[debug] dequeue_prog: 0 instances of #27249
[debug] dequeue_prog(#68733, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#68733, 1)
[debug] dequeue_prog: 0 instances of #68733
[debug] dequeue_prog(#73540, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#73540, 1)
[debug] dequeue_prog: 0 instances of #73540
[debug] dequeue_prog(#75066, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#75066, 1)
[debug] dequeue_prog: 0 instances of #75066
[debug] dequeue_prog(#76525, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#76525, 1)
[debug] dequeue_prog: 0 instances of #76525
[debug] dequeue_prog(#79016, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#79016, 1)
[debug] dequeue_prog: 0 instances of #79016
[debug] dequeue_prog(#87549, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(3): about to muf_event_dequeue(#87549, 1)
[debug] dequeue_prog: 0 instances of #87549
[debug] dequeue_prog(#99026, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#99026, 1)
[debug] dequeue_prog: 0 instances of #99026
[debug] dequeue_prog(#116192, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#116192, 1)
[debug] dequeue_prog: 0 instances of #116192
[debug] dequeue_prog(#123836, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#123836, 1)
[debug] dequeue_prog: 0 instances of #123836
[debug] dequeue_prog(#145112, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#123836, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#145112, 1)
[debug] dequeue_prog: 0 instances of #145112
[debug] dequeue_prog(#164389, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#123836, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#145112, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#164389, 1)
[debug] dequeue_prog: 0 instances of #164389
[debug] dequeue_prog(#170646, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#123836, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#145112, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#164389, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#170646, 1)
[debug] dequeue_prog: 0 instances of #170646
[debug] dequeue_prog(#173282, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#123836, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#145112, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#164389, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#170646, has_refs()=0 ptr->uid=#182194.
dequeue_prog(3): about to muf_event_dequeue(#173282, 1)
[debug] dequeue_prog: 0 instances of #173282
[debug] dequeue_prog(#180634, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133de720
dequeue_prog: tqhead->called_prog = #171, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#2385, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#7335, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#123836, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#145112, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#164389, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#170646, has_refs()=0 ptr->uid=#182194.
dequeue_prog(2): ptr->called_prog=#173282, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#180634, 1)
[debug] dequeue_prog: 0 instances of #180634
LOADING: /opt/fuzzball/spr/game/data/std-db.db (done)
Checking objects 0 to 9999...
Checking objects 10000 to 19999...
Checking objects 20000 to 29999...
Checking objects 30000 to 39999...
Checking objects 40000 to 49999...
Checking objects 50000 to 59999...
Checking objects 60000 to 69999...
Checking objects 70000 to 79999...
Checking objects 80000 to 89999...
Checking objects 90000 to 99999...
Checking objects 100000 to 109999...
Checking objects 110000 to 119999...
Checking objects 120000 to 129999...
Checking objects 130000 to 139999...
Checking objects 140000 to 149999...
Checking objects 150000 to 159999...
Checking objects 160000 to 169999...
Checking objects 170000 to 179999...
Checking objects 180000 to 189999...
Checking objects 190000 to 199999...
Checking objects 200000 to 201334...
Searching for orphan objects...
Done.
prog_clean: fr->caller.top=1
Decreasing instances of fr->caller.st[1](#171)
[debug] dequeue_prog(#191413, 1) called from compile.c:1915
dequeue_prog: tqhead = 0x133e80c0
dequeue_prog: tqhead->called_prog = #7335, has_refs = 0 tqhead->uid = #9104
dequeue_prog(2): ptr->called_prog=#9009, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#9680, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#11696, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#27249, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#68733, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#73540, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#75066, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#76525, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#79016, has_refs()=0 ptr->uid=#9104.
dequeue_prog(2): ptr->called_prog=#87549, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#99026, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#116192, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#123836, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#145112, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#164389, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#170646, has_refs()=0 ptr->uid=#182194.
dequeue_prog(2): ptr->called_prog=#173282, has_refs()=0 ptr->uid=#4039.
dequeue_prog(2): ptr->called_prog=#180634, has_refs()=0 ptr->uid=#4039.
dequeue_prog(3): about to muf_event_dequeue(#191413, 1)
[debug] dequeue_prog: 0 instances of #191413
prog_clean: fr->caller.top=1
Decreasing instances of fr->caller.st[1](#7335)
fbmuck: array.c:153: array_tree_find: Assertion `avl != NULL' failed.
PANIC: BAILOUT: caught signal 6
DUMPING: /opt/fuzzball/spr/game/data/std-db.new.PANIC
DUMPING: /opt/fuzzball/spr/game/data/std-db.new.PANIC (done)

Fails to compile with --with-ssl configured

Debian 9.3, OpenSSL 1.1.0f-3+deb9u1, GCC 6.3.0-4.

~/src$ git clone https://github.com/fuzzball-muck/fuzzball.git
Cloning into 'fuzzball'...
remote: Counting objects: 7582, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 7582 (delta 0), reused 1 (delta 0), pack-reused 7579
Receiving objects: 100% (7582/7582), 6.78 MiB | 0 bytes/s, done.
Resolving deltas: 100% (5223/5223), done.
~/src$ cd fuzzball/
~/src/fuzzball$ ./configure --with-ssl --enable-ipv6

TinyMUCK fb7.x auto-configure script.

This script will try and determine things about your system so
that FB can compile correctly. This will create your Makefile
and the header file autoconf.h in the include directory.

checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for gcc option to accept ISO C99... none needed
checking for gcc option to accept ISO Standard C... (cached) none needed
checking how to run the C preprocessor... gcc -E
checking for a BSD-compatible install... /usr/bin/install -c
checking whether C compiler accepts -std=gnu99... yes
checking whether C compiler accepts -fwrapv... yes
checking for cos in -lm... yes
checking for shutdown in -lsocket... no
checking for PCRE directory... /usr
checking for pcre_free in -lpcre... yes
checking for SSL directory... /usr
checking for CRYPTO_free in -lcrypto... yes
checking for SSL_read in -lssl... yes
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for egrep... /bin/grep -E                                                                          [295/609]
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking malloc.h usability... yes
checking malloc.h presence... yes
checking for malloc.h... yes
checking sys/resource.h usability... yes
checking sys/resource.h presence... yes
checking for sys/resource.h... yes
checking sys/signal.h usability... yes
checking sys/signal.h presence... yes
checking for sys/signal.h... yes
checking whether time.h and sys/time.h may both be included... yes
checking sys/time.h usability... yes
checking sys/time.h presence... yes
checking for sys/time.h... yes
checking varargs.h usability... no
checking varargs.h presence... no
checking for varargs.h... no
checking stdarg.h usability... yes
checking stdarg.h presence... yes
checking for stdarg.h... yes
checking errno.h usability... yes
checking errno.h presence... yes
checking for errno.h... yes
checking sys/errno.h usability... yes
checking sys/errno.h presence... yes
checking for sys/errno.h... yes
checking for dirent.h that defines DIR... yes
checking for library containing opendir... none required
checking size of long int... 8
checking size of int... 4
checking for pid_t... yes
checking for size_t... yes
checking return type of signal handlers... void
checking whether struct tm is in sys/time.h or time.h... time.h
checking for struct tm.tm_zone... yes
checking for struct tm.tm_gmtoff... yes
checking for mallinfo... yes
checking for getrlimit... yes
checking for getrusage... yes
checking for random... yes
checking for pselect... yes
checking for struct mallinfo.hblks... no
checking for struct mallinfo.keepcost... no
checking for struct mallinfo.treeoverhead... no
checking for struct mallinfo.grain... no
checking for struct mallinfo.allocated... no
checking for struct tm.tm_gmtoff... no
checking whether _timezone is declared... no
checking for an ANSI C-conforming const... yes
checking for long double with more range or precision than double... yes
checking for long long int... yes
checking for long double with more range or precision than double... yes                                    [236/609]
checking for long long int... yes
checking value of uname -a
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating game/restart
config.status: creating include/autoconf.h

You should review the options in include/config.h, and
then type make to build your system.

~/src/fuzzball$ make
for d in src; do \
        cd ${d} && make all; \
done
make[1]: Entering directory '/home/jcoffman/src/fuzzball/src'
Creating ../include/defines.h...
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c array.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c boolexp.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c compile.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c create.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c db.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c debugger.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c diskprop.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c edit.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c events.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c fbmath.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c fbsignal.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c fbstrings.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c fbtime.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c game.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c hashtab.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c help.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c interface_ssl.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c interp.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c log.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c look.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c match.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c mcp.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c mcpgui.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c mcppkgs.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c mfuns.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c mfuns2.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c move.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c msgparse.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c mufevent.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_array.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_connects.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_db.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_error.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_float.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_math.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_mcp.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_misc.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_props.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_regex.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_stack.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c p_strings.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c player.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c predicates.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c player.c                     
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c predicates.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c propdirs.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c property.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c props.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c rob.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c sanity.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c set.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c sha1.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c speech.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c timequeue.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c tune.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c wiz.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c crt_malloc.c
gcc -g -O2 -std=gnu99 -fwrapv  -I../include  -I/usr/include -I/usr/include  -c interface.c
interface.c: In function ‘configure_new_ssl_ctx’:
interface.c:2060:9: error: ‘ctx’ undeclared (first use in this function)
     if (ctx->config->dheparams == -1)
         ^~~
interface.c:2060:9: note: each undeclared identifier is reported only once for each function it appears in
Makefile:145: recipe for target 'interface.o' failed
make[1]: *** [interface.o] Error 1
make[1]: Leaving directory '/home/jcoffman/src/fuzzball/src'
Makefile:12: recipe for target 'all' failed
make: *** [all] Error 2

Expose TLS cipher modes in status log on connect

In my ongoing attempt to improve the security posture of MUCK servers and their clients, I'm trying to collect data on what TLS mode is being negotiated with each client as it connects in order to determine what clients will be affected by security configuration changes, such as the one motivated by the ROBOT attack.

That information is currently only presented to the client, and only for those clients lucky enough to use software that even bothers to report that data. Can we add data to the status log that indicates what cipher suite is used when a connection is established?

Recursive interpreter invocations can stall MUCK for exteremely long time even with PREEMPT and nesting limits

A MUF program that does something like:
: main begin 0 try prog #1 "foo" interp pop catch pop endcatch repeat ;
can stall the MUCK for a very, very long time with just M3 permissions. A similar program using TESTLOCK can stall the MUCK for a very, very long time with only M1 permissions.

We enforce a limit of 8 levels of nesting, but given the default PREEMPT instruction limit of 10k, this allows:

  • around 2k INTERP (or TESTLOCK) calls at level 0
  • 2k INTERP calls for each of those INTERP calls at level 1
  • 2k INTERP calls for each of those INTERP calls at level 2
  • ...

which might as well not be an instruction limit, even with a rather modest level of nesting.

One fix would be to limit total instructions executed recursively by any interp_loop() call (at least for non-M4 code). Another approach would be to limit the total number of interp_loop() calls, not just the number of levels of interp_loop() calls.

PREEMPT primitive generates MUF compiler error

On SPR, we have the following object:

whengraph.muf(#7335FLAVM3)  Owner: SPR
Type: PROGRAM  Flags: LINK_OK MUCKER3 VIEWABLE AUTOSTART
A scroll containing a spell called whengraph.muf
Created:  Sat Jul 29 13:19:00 UTC 1995
Modified: Sun Apr 23 23:18:47 UTC 2017
Lastused: Sun Apr 23 23:29:00 UTC 2017
Usecount: 9653831     Instances: 0
[ Use 'examine <object>=/' to list root properties. ]
Memory used: 3342 bytes
Program not compiled.

When I attempt to compile/use the program, I receive the following error:

Program not compilable. Cannot run.

The following is recorded in logs/muf-errors:

2017-04-23T23:46:13: SPR(#9104) [whengraph.muf(#7335)] SPR(#9104) Error in line 2: Number outside procedure.

Nothing was changed aside from pulling the latest (as of this date) code changes and recompiling on our sandbox system.

Output of @list #7335=1-10:

(WhenGraph - Another W* Program by Riss! 6/6/95)
PREEMPT
var CC
var scale
var dif
: dohelp
 "WhenGraph - By Riss - Ver 1.2" .tell
 " WG       - Displays a graph of the last 24 hours low and" .tell
 "             counts of connections to the server. " .tell
 " WG #dif  - Same display but with differential graph." .tell
10 lines displayed.

Is there an issue with the PREEMPT primitive that's generating this error? Is PREEMPT now required to be used within a MUF word rather than outside?

MUF bitwise operators process floats weirdly

The MUF bitwise operators use the same pattern as other arithmetic operations to decide on result types. This means that 0.0 0.0 BITAND produce a float result. However, the calculation is not done in a way which takes into account that floats are being used (including potentially accessing some out-of-bounds memory when using a pointer to an int containing the result as a pointer to float).

OSX won't compile without pcre

Reported to me by Puck of HLM:

The OS X build environment does not include pcre by default. FB's configure script has an option for --without-pcre which it accepts. However the actual make still fails with 'pcre.h not found' so either it needs to be specified that pcre is required (it can be added to OS X, it's just not there by default) or the configure/make stuff needs to be fixed to be able to correctly build without pcre.

array_tree_compare is not transitive, sometimes divides by zero

array_tree_compare tries to compare floats using a margin of DBL_EPSILON, but this means that its comparison is not transitive. It also uses division by one of the values being compared to scale this comparison, which sometimes divides by zero.

The division by zero definitely needs to get fixed. Any change to array_tree_compare probably changes the user-visible semantics of MUF dictionaries.

memory leak from nested arrays and array_pin

Nested arrays and array_pin can leak memory. For example, the MUF program:

: main { }dict ARRAY_PIN DUP 0 ARRAY_SETITEM DUP DUP ARRAY_SETITEM ;

leaks memory (AddressSanitizer report):

=================================================================
==7216==ERROR: LeakSanitizer: detected memory leaks
                                      
Indirect leak of 56 byte(s) in 1 object(s) allocated from:
    #0 0x4d0730 in calloc (/home/charles/software/fbmuck-code2/src/fbmuck+0x4d0730)
    #1 0x50ca16 in array_tree_alloc_node /home/charles/software/fbmuck-code2/src/array.c:303:31
    #2 0x50ca16 in array_tree_insert /home/charles/software/fbmuck-code2/src/array.c:355
    #3 0x50a9e4 in array_setitem /home/charles/software/fbmuck-code2/src/array.c:931:7
    #4 0x5d287c in prim_array_setitem /home/charles/software/fbmuck-code2/src/p_array.c:338:14
    #5 0x57b4c2 in interp_loop /home/charles/software/fbmuck-code2/src/interp.c:1726:3
    #6 0x5bd24a in do_move /home/charles/software/fbmuck-code2/src/move.c:485:6
    #7 0x568b68 in process_command /home/charles/software/fbmuck-code2/src/game.c
    #8 0x6e3d17 in do_command /home/charles/software/fbmuck-code2/src/interface.c:1000:6
    #9 0x6e3d17 in process_commands /home/charles/software/fbmuck-code2/src/interface.c:1071
    #10 0x6e3d17 in shovechars /home/charles/software/fbmuck-code2/src/interface.c:2324
    #11 0x6e1991 in main /home/charles/software/fbmuck-code2/src/interface.c:4532:2
    #12 0x7f8d7e11b3f0 in __libc_start_main /build/glibc-mXZSwJ/glibc-2.24/csu/../csu/libc-start.c:291
                
Indirect leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x4d0538 in malloc (/home/charles/software/fbmuck-code2/src/fbmuck+0x4d0538)
    #1 0x509971 in new_array /home/charles/software/fbmuck-code2/src/array.c:526:24
    #2 0x509971 in new_array_dictionary /home/charles/software/fbmuck-code2/src/array.c:574
    #3 0x5ceff9 in prim_array_make_dict /home/charles/software/fbmuck-code2/src/p_array.c:75:10
    #4 0x57b4c2 in interp_loop /home/charles/software/fbmuck-code2/src/interp.c:1726:3
    #5 0x5bd24a in do_move /home/charles/software/fbmuck-code2/src/move.c:485:6
    #6 0x568b68 in process_command /home/charles/software/fbmuck-code2/src/game.c
    #7 0x6e3d17 in do_command /home/charles/software/fbmuck-code2/src/interface.c:1000:6
    #8 0x6e3d17 in process_commands /home/charles/software/fbmuck-code2/src/interface.c:1071                              
    #9 0x6e3d17 in shovechars /home/charles/software/fbmuck-code2/src/interface.c:2324                                        
    #10 0x6e1991 in main /home/charles/software/fbmuck-code2/src/interface.c:4532:2
    #11 0x7f8d7e11b3f0 in __libc_start_main /build/glibc-mXZSwJ/glibc-2.24/csu/../csu/libc-start.c:291                        
 
SUMMARY: AddressSanitizer: 80 byte(s) leaked in 2 allocation(s).

Document YIELD and OVERT.

I could've sworn I saw reasonably complete documentation for what the YIELD and OVERT flags did, once, but I can't find it any more. The best I've been able to come up with is a couple of comments in the middle of src/match.c. They're certainly not documented in the online help with the other user-visible flags, which is something that needs fixing ASAP.

Handling of floating point errors is inconsistent

For the most part, the floating point primitives for MUF handle floating point errors in a non-IEEE way. Typically, they return (positive) INF or 0 on an error and set error flags which can be tested with err_fbounds? err_divzero?, etc. They rarely expose NaN, even though there are FIXMEs in the C code about doing so (e.g. in prim_sin).

Some primitives, however, expose the native NaNs:

  • fmod (e.g. inf inf fmod is NaN)

Some kinds of errors that result in infinity that do not set err_fbounds?, err_imaginary?, etc.:

  • performing inf - inf or nan - anything using diff3
  • performing sqrt(inf) using dist3d

These differences in handling are not documented and seem unintentional.

Proto apparently has an @tune to use IEEE inf/nan instead of trying to convert nans into 0s, which would be a saner approach than making NaNs 0s, but probably not something we can do as our only implementation unless we don't mind breaking some backwards compatibility.

FORCE'ing a user to recompile a program from that program crashes

If a program with dbref 3 contains something like:
: main me @ "@edit #3" force me @ "c" force me @ "Done." notify ;
and runs with appropriate permissions, this will crash. It is probably also possible to trigger this via MUF running MPI that FORCE's a user to do a recompile. (I don't think the @edit command doesn't need to be triggered from MUF, a user who is already editing the program could be FORCE'd.)

Maintainable approach for updating PCRE on Windows

In short

PCRE should be built from source on Windows to keep up with bug-fixes, security improvements, and enable building a 64-bit version of Fuzzball for Windows.

Implementation

To build from source, Makefile.win will need to patch the PCRE directory to build it on Windows, then build it as a .dll, packaging it with the rest of Fuzzball. The Appveyor script will to include pcre.dll in the published artifact.

For long-term ease of maintenance, two approaches come to mind:

Download source package

When building on Windows, the instructions will point to downloading the PCRE source code (e.g. from the official site here) and extracting it in the win32 folder. The Appveyor script will need updated to automatically download PCRE.

  • Benefits
    • Always use the latest released version of PCRE
    • Minimal maintenance effort for Fuzzball
  • Drawbacks
    • Build process depends upon remote server that could have downtime or be hacked. (The Conan.io setup for OpenSSL faces a similar issue, though as a general-purpose package manager they may be less likely to go down)
    • If PCRE makes a breaking change, intentional or accidental, Fuzzball will need updated at the same time

Mirror PCRE repository

Fuzzball will provide a Git mirror of the PCRE source code, either uploading the extracted source package, or directly importing using a tool. The main Fuzzball repository can include the PCRE source as a Git submodule.

  • Benefits
    • Control over the PCRE source, offering reasonable confidence that it's available and consistent
    • Ability to set up separate tests for PCRE, e.g. Appveyor builds
  • Drawbacks
    • Extra maintenance effort to maintain a second repository, especially with getting security updates out in a timely manner
    • Some duplication of effort with copying a repository

Discussion

Both approaches have trade-offs and advantages without a clear winner. More research may be needed to see how other projects approach dependencies.

Other options exist, too - since Conan.io is already used for OpenSSL, a PCRE package could be contributed. Or, though not ideal, a separate repository could contain only PCRE.lib builds, akin to how CyanogenMod handles dependencies.


I pulled this from the email discussion in order to have a single cohesive thread for updates and discussion, keeping it from getting lost.

Issue starting fbmuck 6/7

Opened from e-mail delivered to me:

From: Obscenity Furr (email redacted)

I've tried both fbmuck 6 and 7 and both cant do anything but print the help screen, trying to run a server just flashes another console, I've tried adding '-freeconsole' but the console still flashes, this time creating 0 byte log files.

The systems I've had the same issue on are Ubuntu Server 16.10 and Windows 10. I've also tried compiling it myself, same issue.

Can you help me out?

Missing status logfile prevents startup

Attempting to start the muck while configured with MUD_ID/MUD_GID will result in failed start with the following message, if said file does not already exist:

Unable to open logs/status!

(Expected behavior would be to create the file.)

`@sweep` fails to detect some say/pose/etc. traps

The built-in command @sweep is intended to identify say traps on the environment, but it assumes that say traps will be linked to a MUF program. Therefore, it won't detect some secnario like:

@create ThingWithSayTrap
@act say=ThingWithSayTrap
@lock say=me&!me
@link say=here
@fail say={null:some MPI that does something with {&arg}}
drop ThingWithSayTrap
@sweep

Global scope (room zero) exit is taking priority over a local scope exit when exit priorities are equal.

We use the {flag:} function in our obv-exits macro. Previously, this worked fine. Now it's throwing a permissions error. Can I ask what changed?

Updated: Local exit "spoof" and room zero-linked "spoof" were conflicting. For some reason, when the {flags:} function tried to look at the local "spoof" exit by name, it was getting room zero's copy instead, which was causing a permissions failure. Had to set M3 on the local exit to get the precedence to work right. Same behavior noted with "examine." "ex spoof" was giving me the global version, instead of the local one. What caused this change in behavior?

MATCH not correctly matching in certain cases

Player named "Test" is contained in "Room A." An action named "Test" is located on room zero, Room A's parent room. "Test" match is returning the action, not the player, even when executed in Room A. I believe the player should be matched in this case, as it is the more local object.

Note: I have replicated this issue on FurryMUCK as well as SPR, indicating that this has existed for some time.

fb7a3 release notes issue

Currently says:
[ -rot rot ] => [ rot ]

Should be:
[ rot rot ] => [ -rot ]
[ -rot -rot ] => [ rot ]

because:
[ -rot rot ] => [ (nop) ]

Compile-time option to have @shutdown and @restart generate different process exit codes

Our MUCK is currently managed as a systemd service. Per man systemd.service, systemd has the capability to restart a service on a non-zero process exit code (Restart=on-failure), or on ANY process termination (Restart=always).

Currently, @shutdown and @restart both end the process with exit code 0. This leads to an undesirable behavior where both commands either shut the MUCK down or restart it, depending on the service unit configuration.

I propose having a compile time option (include/config.h most likely) that causes the process to exit with code 0 on @shutdown and something non-zero (perhaps configurable) on @restart.

"examine" command is broken

Examining any room currently reports that room as its own parent. All rooms display this behavior when examined. The following MUF code does correctly report the expected parent:

me @ location location

Allow for specification of a keepalive command

Server-side TCP keepalives can help, but we have a few players that need client-side keepalive capability. I'd like to see a command or a tuneable value that lets us set a command that a player can trigger via client-side timer that generates regular network activity, but does NOT reset their WHO idle time.

@reconfigure_ssl errors can lock out wizards

In short

  • Changed @tune settings are persisted to disk regardless of validity
    • @restart/crashing could result in server not being available
  • @reconfigure_ssl can apply valid settings that lock out wizards
    • E.g. selecting TLSv1.2 (higher is more secure, right?) when using TLSv1.1 client
    • What works for some wizards might lock out other wizards
  • @reconfigure_ssl/@tune does not allow reverting to "last known working" settings
Criteria Rank Reason
Impact ★★☆ 2/3 Resolves server lock-out that requires wizard access to cause
Risk ★★☆ 2/3 Possible subtle errors, but testing should catch most
Intrusiveness ★★☆ 2/3 May require settings overhaul, SSL refactoring

Implementation

No firm implementations have been decided on yet.

In general, this requires some way of storing a last-known good configuration and requiring confirmation before persisting.

Apply on fly, offer no reversion

  • Good
    • Already implemented
    • Less complicated/error-prone
  • Bad
    • Could result in locking out wizards/regular players

Apply on the fly, revert after time delay/crash/@restart

  • Good
    • Allows testing configuration before confirming
    • No additional port required
  • Bad
    • Affects all incoming connections, if broken very noticeable
    • Only allows short-term testing
    • More complicated

Provide alternative port for testing configuration changes

  • Good
    • Works for long-term testing
    • Doesn't interrupt existing/new connections
  • Bad
    • Requires additional port, additional resources
    • Requires reserving port during start-up given privilege dropping
    • Even more complicated

Other options..?

Discussion

There's other options, and almost certainly other trade-offs I haven't considered. I'm not sure of what's the best approach.


I pulled this from the email discussion in order to have a single cohesive thread for updates and discussion, keeping it from getting lost. Thanks to Wyld, Kyle, and Keet for your comments!

Document XFORCIBLE

The XFORCIBLE flag is mentioned in the documentation for @set and @force, but the documentation for the flag itself seems to have gotten lost at some point. Additionally, I don't think its use on exits/actions (displayed as XPRESS) was ever documented anywhere.

lock parsing/unparsing/etc. can use a lot of stack space

The lock parsing/evaluation/unparsing code is recursive and the only limits on the number of levels are based on what can be fit in a (~8KB) lock string. It might be wise to have some explicit depth limit rather than have a way that users might be able to make the MUCK run out of stack space.

User passwords stored using insecure algorithm

All user passwords are currently stored according to the following algorithm:

base64(md5(password))

Using MD5 is, these days, little better than obfuscation, rather than proper security. Combined with a lack of salting, it is trivial to recover user passwords with access to the database.

Salting passwords prior to storage would greatly increase the time to recovery for dictionary and brute-force offline attacks, though with MD5 as the underlying hash, it would still be well within the capability of the average attacker.

Ideally, MD5 would be replaced with a proper key derivation function (bcrypt, PBKDF2, et al.), or at least a multi-round SHA2 digest.

Both of these (salting, algorithm) could be implemented as compile-time options so as not to automatically modify a database in such a way that compatibility is broken with prior versions.

Choose and automatically apply coding style

In short

  • Choose a coding style
    • Tabs? Spaces? (Both, i.e. smart tab?) Variable naming?
    • May be best to compare with other large and/or long-standing projects
    • Highly subjective
  • Automatically apply this coding style
Criteria Rank Reason
Impact ★★☆ 2/3 Not user-facing, but improves developer quality-of-life
Risk ★☆☆ 1/3 Style won't cause issues, automated tools may complicate contributing
Intrusiveness ★★★ 3/3 Will modify almost every single file, not easily reverted

Discussion

...I've yet to see enough projects to have a strong view. Quassel uses 4 spaces, Ceph uses both (smarttab - apparently also controversial), etc.

Discuss in comments?


I pulled this from the email discussion in order to have a single cohesive thread for updates and discussion, keeping it from getting lost.

MUF and FuzzBall

Just out of curiosity (no rush as the changes aren't urgent):
I noticed in the fuzzball repository, there's this directory:
dbs/advancedb/muf
It has the same stuff (pretty much) that the fuzzball-muf repository has. When/how do changes move from fuzzball-muf to fuzzball itself?
I'm mostly used to mailing lists, so I apologise in advance for being so goofy with github. I don't know how else to contact you guys! Thanks for reading my question!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.