summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
...
* Version 279.txr-279Kaz Kylheku2022-08-086-1051/+1095
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated.
* path-components-safe: proc tests only on Linux.Kaz Kylheku2022-07-301-18/+20
| | | | | | | * stdlib/path-test.tl (safe-abs-path): If (uname) doesn't report Linux, then define this function in a way that it always returns true. We do this by making the name an alias for the tf function.
* path-components-safe: check symlink link count.Kaz Kylheku2022-07-301-2/+3
| | | | | | * stdlib/path-test.tl (path-components-safe): Reject symlinks that have a link count not equal to one. This looks suspiciously like a hard link attack.
* path-components-safe: tighten /proc checkKaz Kylheku2022-07-302-45/+35
| | | | | | | | | | | | | | Attacks are possible via /proc/<pid>/fd/<n> involving a deleted file, whereby the link target changes from "/path/to/file" to "/path/to/file (deleted)", which can be perpetrated by a different user, not related to process <pid>, who has access to perform unlink("/path/to/file"). * stdlib/path-test.tl (safe-abs-path): Perform the pattern check regardless of effective user ID. * tests/018/path-safe.tl: Test cases adjusted.
* path-components-safe: handle consecutive slashes.Kaz Kylheku2022-07-301-4/+2
| | | | | * stdlib/path-test (path-components-safe): Remove empty components from split path.
* path-components-safe: repel /proc symlink attacksKaz Kylheku2022-07-292-17/+67
| | | | | | | | | | | | | | | | | | | | | | In a Linux system, it's possible for an unprivileged user to create a root symlink pointing to any directory, simply by changing to that directory and running a setuid executable like "su". That executable will get a process whose /proc/<pid> directory is root owned, and contains a symlink named cwd pointing to the current directory. Other symlinks under /proc look exploitable in this way. * stdlib/path-test.tl (safe-abs-path): New function. Here is where we are going to check for unsafe paths. We use some pattern matching to recognize various unsafe symlinks under /proc. (path-components-safe): Simplify code around recognition of absolute paths. When an absolute path is read from a symlink, remove the first empty component. Pass every absolute path through safe-abs-path to check for known unsafe paths. * tests/018/path-safe.tl: New tests.
* rel-path, path-equal: relocate.Kaz Kylheku2022-07-293-107/+96
| | | | | | | | * stdlib/copy-file.tl (path-simplify, path-split, path-volume, rel-path, path-equal): Remove from here. * stdlib/path-test.tl: (path-simplify, path-split, path-volume, rel-path, path-equal): Move to here.
* stringp: rewrite.Kaz Kylheku2022-07-281-5/+13
| | | | | | * lib.c (stringp): Examine tag and then type separately, rather than using the canned type function. This leads to slightly nicer code, shorter by a couple of instructions.
* gcd: rewrite for better efficiency.Kaz Kylheku2022-07-272-24/+104
| | | | | | | | | | | * arith.c (gcd): New implementation which uses arithmetic in the unsigned type ucnum if both operands are in that type's range. This uses Stein's algorithm a.k.a. binary GCD. The mpi_gcd function is used only if at least one argument is a bignum whose value doesn't fit into a ucnum. * tests/016/arith.tl: gcd test cases added.
* in6addr-str: remove useless regsub.Kaz Kylheku2022-07-271-1/+0
| | | | | | | | * stdlib/socket.tl (in6addr-str): Remove one of the two repetitions of a string substitution intended to be done once. The substitution is idempotent and therefore a second application of it is redundant regardless of intent.
* Take advantage of substring support in regsub.Kaz Kylheku2022-07-274-8/+5
| | | | | | | | | | | | | | | | * txr.c (sysroot_init): Use regsub to look for "\\" substring instead of regex. * stdlib/getopts.tl (opt-parsed convert-type): regsub for "0x" substring rather than #/0x/ regex. * stdlib/pic.tl (pic-join-oipt): regsub for "~" substring rather than #/\~/ regex. * stdlib/socket.tl (in6addr-str): regsub for "::" substring instead of #/::/ regex in two places. The double regsub there looks like a mistake; will address in another commit.
* regsub: allow string in place of regex.Kaz Kylheku2022-07-272-4/+24
| | | | | | * regex.c (regsub): Use search_str if regex is a string. * txr.1: Documented.
* regsub: avoid consing list.Kaz Kylheku2022-07-271-10/+10
| | | | | | * regex.c (regsub): Accumulate output string directly using string_extend, rather than accumulating a list of pieces which are catenated with cat_str.
* repl: revise security checks.Kaz Kylheku2022-07-262-33/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Summary: we now check the entire path of .txr_history and .txr_profile files for security issues; we enforce that these files must not be readable to other users, not just not writable. And there is a bugfix: we do not load the history if it has a permission problem, instead of loading it anyway and just issuing a diagnostic. * repl.c (report_security_problem): Rename to report_file_perm_problem. Drop the umask check, because we are going to be checking for files that are not readable for others, which would require a stricter umask than the usual 022. (report_path_perm_problem): New static function. (load_rcfile): Take the needed function symbols as arguments, because the only caller is repl and it has them; it can pass them down. Check the path using path-components-safe function, and bail with an error message if it is bad. Then check the file using path-strictly-private-to-me-p, rather than path-private-to-me-p as previously. This requires the file not to be readable to others too. (repl): path_private_to_me_p variable renamed to ppriv_s for brevity and holds a different symbol: path-strictly-private-to-me-p, the function which checks that other users cannot read the file, not just write. Also capture the path-components-safe symbol as psafe_s. ppriv_s and psafe_s are passed down to load_rcfile so it can do checks. Like in the case of the rcfile, we now check the history file using both functions, validating the path not just the file's own permissions. Bugfix: we now check the history file's path before loading the history file, and avoid loading it if the check fails. We use the path-exists-p function now to check that the history and rc files exist. That leaves a small flaw: an attacker could be in control of the paths to these files and manipulate these paths such that these files appear not to exist; we will then not report on such a situation. * txr.1: Documented.
* path-components-safe: refactoring.Kaz Kylheku2022-07-252-56/+39
| | | | | | | | * stdlib/path-test.tl (path-components-safe): Simplify code; forget trying to do anything on Windows: just return true. * txr.1: Document that path-components-safe is useless on Windows.
* New function: path-components-safe.Kaz Kylheku2022-07-255-20/+203
| | | | | | | | | | | | | | | | * autoload.c (path_test_set_entries): Autoload on path-components-safe symbol. * stdlib/path-test.tl (if-windows, if-native-windows): New system macros. (path-safe-sticky-dir): New system function. (path-components-safe): New function. * tests/018/path-safe.tl: New file.' * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* path-test: object trust must use effective UID.Kaz Kylheku2022-07-242-10/+22
| | | | | | | | | * stdlib/path-test.tl (path-private-to-me, path-strictly-private-to-me): Call (getuid) rather than (geteuid). We won't revert this behavior with the -C compat option because it's wrong/insecure. * txr.1: Updated.
* compile-file: distinguish nonexistence errors.Kaz Kylheku2022-07-211-8/+10
| | | | | | | | | | | | | | | | | | | The compile-file function must only try a different path, such as with a suffix, if a given path fails to open due to non-existence. If the failure is for another reason, like permissions. In that case we want to propagate the failure. * stdlib/compiler.tl (ign-notfound): New macro. This lets through all errors, catching only path-not-found, converting that to a nil result. (open-compile-streams): Use ign-notfound instead of ignerr when trying to open an input file for reading. Also, we lose the ignerr wrapping around the open-file. We let any error whatsoever just bubble out so that the user is better informed about what went wrong. The requirement to close the input stream is handled by the obvious unwind-protect.
* compile-file: revise hash bang treatment.Kaz Kylheku2022-07-212-7/+27
| | | | | | | | | * stdlib/compiler.tl (translate-hash-bang): New function. (compile-file-conditionally): Use translate-hash-bang to treat hash bang line. * txr.1: Revised hash bang treatment by file compiler documented.
* compiler: try unsuffixed path before adding .tlKaz Kylheku2022-07-212-6/+6
| | | | | | | | * stdlib/compiler.tl (open-compile-streams): If the in-path is unsuffixed, try opening it without adding any suffix first. If that fails, then try .tl in that order. * txr.1: Documented.
* syrooting: remove two useless checks.Kaz Kylheku2022-07-211-2/+0
| | | | | | | | | | | | * txr.c (sysroot_init): The value of TXR_REL_PATH already has the exe suffix on it if we are building for Windows. There is no need to try with EXE_SUFF tacked on to it. There is also no need to try PROG_NAME with or without the suffix. EXE_SUFF is the empty string on non-Windows platforms, so the two lines of code are equivalent. On Windows, PROG_NAME without the EXE_SUFF will not match; that maybe_sysroot call is a waste of CPU cycles.
* Install a txrlisp hard link.Kaz Kylheku2022-07-213-0/+45
| | | | | | | | | | | | | | | | | | * Makefile (LN): New variable. On platforms where you can't hard link, this can be replaced with some other command. Possibly "true" not to have the alternative executable name created at all. (HARDLINK): New macro. (install): Use HARDLINK to create a link named txrlisp pointing to the same file as txr in the destination directory. * txr.c (txr_main): If the executable ends with "lisp" (or "lisp.exe" on Windows), then default the txr_lisp_p variable to t, which has the effect as if --lisp had been processed. * txr.1: Documented.
* doc: pos function.Kaz Kylheku2022-07-181-5/+9
| | | | * txr.1: Improve unclear wording describing pos function.
* New function: count.Kaz Kylheku2022-07-186-20/+94
| | | | | | | | | | | | | | | | The general count function, with keyfun and testfun, is noticeably absent. Let's implement it. * lib.[ch] (count): New function. * eval.c (eval_init): Register count intrinsic. * tests/012/seq.tl: Some tests for count. * txr.1: Add count to count-if section. Revise documentation based on pos/pos-if. * stdlib/doc-syms.tl: Updated.
* Date correction; man page typos.txr-278Kaz Kylheku2022-07-012-4/+4
| | | | | | * RELNOTES: 2022-07-01. * txr.1: Likewise and two minor fixes.
* Version 278.Kaz Kylheku2022-07-015-5/+44
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * protsym.c: Regenerated.
* doc: remove references to non-fork platforms.Kaz Kylheku2022-06-291-16/+3
| | | | | | | | | * txr.1: Remove references to limitations in open-process on platforms which don't have fork. It's simply not implemented on those platforms at all any more. This documentation referred to a MinGW port of TXR which has not been maintained in many years. Also remove text which says that open-subprocess is only available on platforms with fork.
* Add mode-opt to all I/O convenience functions.Kaz Kylheku2022-06-292-33/+33
| | | | | | | | | | | * stdlib/getput.tl (command-get, command-put, command-get-string, command-put-string, command-get-lines, command-put-lines, command-put-buf, command-get-json, command-put-json, command-get-jsons, command-put-jsons): Add mopt parameter, which is interpolated into appropriate mode string. This allows "z" to be used for gzip compression. * txr.1: Updated Syntax synopses.
* file-get-lines: missing mode-opt parameter.Kaz Kylheku2022-06-291-2/+2
| | | | | * stdlib/getput.tl (file-get-lines): A mode-opt parameter is documented for this function; it is now actually implemented.
* close-stream: process wait cleanup.Kaz Kylheku2022-06-241-18/+6
| | | | | | | | | * stream.c (pipe_close_status_helper): Revise error messages. Get rid of impossible cases: we will not get WIFSTOPPED or WIFCONTINUED unless we used the WUNTRACED option in waitpid, which we don't. No platforms without HAVE_SYS_WAIT, don't throw if the status is nonzero; just return nil. It could be a normal termination.
* doc: document pid argument of open-fileno.Kaz Kylheku2022-06-241-2/+37
| | | | | | * txr.1: pid argument is documented and also missing, documentation added about how close-stream deals with processes.
* More HAVE_FORK_STUFF cleanup.Kaz Kylheku2022-06-241-3/+3
| | | | | | * stream.c (pipe_close_status_helper, pipe_close, pipe_ops): Included in #if HAVE_FORK_STUFF block. (stream_init): Refer to pipe ops only if HAVE_FORK_STUFF is true.
* streams: remove old code for popen on MingGW.Kaz Kylheku2022-06-214-174/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is vestigial code from a time when TXR supported being compiled with MinGW. Except in the case of the functions run and sh, which are implementable without fork on Cygwin using the spawn family of functions, there won't be any fallback; if HAVE_FORK_STUFF is zero or missing, then certain functions will be absent. * stream.c (struct stdio_handle): Do not define a pid member if we don't HAVE_FORK_STUFF. (se_pclose): Function removed; we won't be using any non-POSIX platforms popen/pclose. (pipe_close): Don't call the removed se_pclose. (make_pipe_stream): Function removed. (fds_subst, fds_swizzle): Don't define these if HAVE_FORK_STUFF is absent, and so is HAVE_WSPAWN and HAVE_SPAWN. They are now only needed by the version of the run function that uses spawn or wspawn. (open_command, open_process): Remove the versions of these function based on popen. (string_extend_count, win_escape_cmd, win_escape_arg, win_make_cmdline): Remove these functions used by the above open_process; we have no need for encoding arguments into a Windows command line string, since the Cygwin/Cygnal libraries do that for us in their spawn and exec functions. * stream.h (make_pipe_stream): Function removed. * utf8.[ch] (w_popen): Function removed.
* bugfix: missing gzip support in open-command.Kaz Kylheku2022-06-216-55/+118
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * stream.c (pipe_close_status_helper): New function, factored out of pipe_close and used by it, and also by gzio_close. (pipe_close): Call pipe_close, which now contains the classification of process wait status codes. (open_fileno): Now takes optional pid argument. If this specified, then make_pipevp_stream is used. (open_subprocess): Use the open_fileno function, rather than fopen. This simplifies things too, except that we have to catch exception. Pass pid to the newly added parameter of open_fileno so that we obtain a proper pipe stream that will wait for the process to terminate when closed. (mkstemp_wrap): Pass nil for pid argument of open_fileno. (stream_init): Update registration of open-fileno. * gzio.c (struct gzio_handle): New member, pid. (gzio_close): If there is a nonzero pid, wait for the process to terminate. (make_gzio_stream): Initialize h->pid to zero. (make_gzio_pipe_stream): New function. * parser.c (lino_fdopen): Pass nil for pid argument of open_fileno. * gzio.h (make_gzio_pipe_stream): Declared. * tests/018/gzip.tl: New test.
* configure: remove unused android_targetKaz Kylheku2022-06-211-2/+0
| | | | * configure (android_target): Remove unused variable.
* for/for*: stricter syntax check.Kaz Kylheku2022-06-133-18/+19
| | | | | | | | | | | | | | | | | * eval.c (me_for): Require at least one argument. However, we let the init-forms continue to be optional and document it. * txr.1: Refer to for and for* as macros, since they have been since 2016. The omission of the inc-form list is shown as a second variant of the syntax. This is to avoid misleading the reader into thinking that the the inc-form list can be omitted while body forms are present. A spurious paragraph reiterating that the macros establish an anonymous block is removed. That extra text was present in the first draft written in 2011, and maintained since. * stdlib/doc-syms.tl: Updated.
* New function: strKaz Kylheku2022-06-126-40/+136
| | | | | | | | | | | | | | | The str function is like mkstring but allows a fill pattern to be specified. * eval.c (eval_init): str intrinsic registered. * lib.[ch[ (str): New function. * tests/015/str.tl: New file. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* optimizer: fix live set being unexpectedly nil.Kaz Kylheku2022-06-091-2/+2
| | | | | | | | | | | | | | | | | | | | The following test case throws an exception: (compile-toplevel '(when-match @(or @b @c) nil nil)) the reason is that in the optimizer, the local-liveness method resets the bl.live set of live registers to nil. The expectation is that it will be recalculated. However, what happens is that * stdlib/optimize.tl (basic-block): Initialize live slot to zero. (basic-blocks local-liveness): Reset bl.live to 0, rather than nil. The problem is that sometimes the block in question is not reached in the graph traversal (down in the same function) which is supposed to assign it a live value. This happens in the above test case, and it's not due to any bug: the block is not reached by the forward traversal because the block has become unreachable.
* optimizer: remove root slot from basic-block.Kaz Kylheku2022-06-091-6/+3
| | | | | | | | | | | | | | The root slot is just supposed to be (car bl.list): the first basic block. Unfortunately, it's not maintained when bl.list is edited, which could cause bugs. This change makes no difference in the stdlib compiled files, other than of course the changes in optimize.tlo from this code change itself; so that is evidence suggesting this change is least not making anything worse. * stdlib/optimize.tl (basic-blocks): Remove root slot. (basic-blocks (link-graph, calc-liveness, elim-dead-code): Refer to (car bl.list) instead of bl.root.
* listener: bugfix: handle warnings around linenoise.Kaz Kylheku2022-06-081-0/+4
| | | | | | | | | | | * parser.c (repl): Also push and pop the warning handler around the linenoise call, like we do around evaluation. The reason is that when the library is used in source code form, it can generate warnings while loading. Loading can be triggered by completion from inside linenoise. Neglecting to handle warnings and throw a continue causes a problem because the warnings then fall victim to the listener's master catch. That then interferes with the load.
* string-out-stream: gc issue.Kaz Kylheku2022-06-061-3/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The problem being addressed here showed up for me when compiling with either gcc-7 or gcc-11 on Ubuntu 18, using -fsanitize-undefined. A few test test cases run under --gc-debug were crashing. I narrowed it down to this small test case, whose correct output would be "1": ./txr --gc-debug -p '(sys:fmt-simple 1 : : : :)' "\x6700ACB0缻\x6700ACB0缻 " The issue doesn't have anything to do with -fsanitize-undefined; that just how it got reproduced by chance. I'm reasonably certain that in builds for which "make tests" passes, and the above test case doesn't repro, this issue is absent: the code got generated in such a way that it the string_own call doesn't cause the stream object to be reclaimed. * stream.c (get_string_from_stream): change the order of operations in the ownership transfer of the string from the stream to the returned string object. We capture the string in a local variable, and null out so->buf before calling string_own. The problem is that get_string_from_stream is called in a way where the caller no longer has any use for the stream, and so the object is no longer live. It's possible for the string_own call to cause the stream object to be garbage collected. Therefore, the object must not still be hanging on to the wchar_t * string, which was already transferred to the string object.
* txr: fix --free-all crash due to atexit order.Kaz Kylheku2022-06-053-14/+15
| | | | | | | | | | | | | | | | | | | | | | | | The --free-all feature is broken. It is needed for confirming lack of memory leaks during development. What breaks it is the atexit call to run_load_hooks in eval.c, which occurs after the atexit call to free_all in txr.c which blows everything away. * Makefile (tst/tests/019/load-hook.ok): Let's put --free-all on this test case, because it has to with the load hooks. Make no mistake though: everything crashes with --free-all, not this test case specifically. * txr.c (opt_free_all): New global variable. (free_all): Free resources only if opt_free_all is true. Lose the paranoid called flag. (main): Register free_all with atexit before callilng init. This ensures that it will be called after any atexit handlers registered as part of init, like the one in sysif.c and eval.c. (txr_main): The --free-all option now just sets opt_free_all. * txr.h (opt_free_all): Declared.
* doc: missing word in tree-insert section.Kaz Kylheku2022-06-011-0/+1
| | | | * txr.1: Add missing "If" at start of sentence.
* build: fix broken build when we don't HAVE_ZLIB.Kaz Kylheku2022-05-312-0/+21
| | | | | | | | | | | * parser.c (open_txr_file): Use liberal heaps of #if HAVE_ZLIB. If there is no Zlib, and the caller explicitly requests a .tlo.gz file to be loaded, then throw. Do not implicitly look for a .tlo.gz file. * stream.c (open_file): #if HAVE_ZLIB around a goto label that is only used out of HAVE_ZLIB code, to eliminate unused label warning.
* streams: use ~a for self string.Kaz Kylheku2022-05-311-3/+3
| | | | | | * stream.c (parse_mode, open_file, open_fileno): Since self is a string, use ~a to print it, or else quotes will appear.
* Version 277.txr-277Kaz Kylheku2022-05-316-1123/+1158
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated.
* crc32: name clash with Zlib on Android.Kaz Kylheku2022-05-312-3/+2
| | | | | | | * chksum.c (crc32): Stop-gap solution: make it static. Also, fix wrong self-string. * chksum.h (crc32): Declaration removed.
* windows: bundle Zlib in installer.Kaz Kylheku2022-05-311-0/+1
| | | | * inst.nsi: pull in cygz.dll.
* cygwin: bug: sh always uses cmd.exe.Kaz Kylheku2022-05-312-18/+7
| | | | | | | | | | * stream.c (sh): Use a single definition for this function, which uses the shell and shell_arg variables to use either /bin/sh -c or cmd.exe /c. We only want to use cmd.exe when running as a Windows native program on Cygnal. * tests/018/process.tl: Remove workaround from test case. This is what was causing the weirdness.
* gzio: unused variable warning.Kaz Kylheku2022-05-311-1/+0
| | | | * gzio.c (gzio_set_prop): Remove unused ops variable.