I have a feeling there is something obvious I'm missing, but my searches are coming up fruitless thus far.
I am trying to use a tcl/expect script to start up a tclsh interactive shell, add a procedure for easily reloading utilities for testing, and then return normal control to me.
So far, the one way I've discovered to make a tcl interactive shell "usable" is to start it with "rlwrap" so that I can use arrow keys, etc.
So I tried the following script and something about rlwrap is causing previous output to be dumped to stdout when the interact command is hit.
Is there something I can do to make this not happen?
Code:
package require Expect
puts "Tcl version : [info tclversion]"
puts "Expect version: [exp_version]"
log_user 0
spawn -noecho rlwrap tclsh
# Create procedure to easily reload utilites after changes have been made
expect "% "
send {
proc reload {} {
# Procedure to reload utility source easily for testing
}
}
# Source utilities
expect "% "
send "reload\r"
send_user "\nUse 'reload' procedure to re-source utility files\n\n"
log_user 1
interact
Output:
Tcl version : 8.4
Expect version: 5.43.0
Use 'reload' procedure to re-source utility files
proc reload {} {
# Procedure to reload utility source easily for testing
}
% reload
%
You can that for some reason it's echoing the proc definition and the entering of the reload command. This occurs as soon as interact occurs. If I replace interact with "exit" I do not see any of this output.
Of course the output I'm hope to see would be this:
Tcl version : 8.4
Expect version: 5.43.0
Use 'reload' procedure to re-source utility files
%
If you don't mind to compile a small C program yourself, you could use this:
#include <tcl.h>
#ifdef WIN32
#ifdef UNICODE
#define WIN32_UNICODE
#endif
#endif
int TclSHI_Main(Tcl_Interp*);
static int g_argc;
#ifdef WIN32_UNICODE
#define Tcl_NewStringObj Tcl_NewUnicodeObj
static wchar_t*** g_argv;
void wmain(int argc, wchar_t **argv) {
#else
static char*** g_argv;
void main(int argc, char **argv) {
#endif
g_argc = argc;
g_argv = &argv;
Tcl_FindExecutable(argv[0]);
Tcl_Main(1, argv, TclSHI_Main);
}
int TclSHI_Main(Tcl_Interp* interp) {
Tcl_Obj* lobj;
int i;
if (g_argc > 1) {
Tcl_SetVar2Ex(interp, "argv0", NULL, Tcl_NewStringObj((*g_argv)[1], -1), TCL_GLOBAL_ONLY);
}
lobj = Tcl_NewObj();
Tcl_IncrRefCount(lobj);
for (i = 2; i < g_argc; i++) {
Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj((*g_argv)[i], -1));
}
Tcl_SetVar2Ex(interp, "argv", NULL, lobj, TCL_GLOBAL_ONLY);
Tcl_DecrRefCount(lobj);
Tcl_SetVar2Ex(interp, "argc", NULL, Tcl_NewIntObj(g_argc - 2), TCL_GLOBAL_ONLY);
if (g_argc > 1) {
Tcl_Eval(interp, "source $argv0");
}
return TCL_OK;
}
I tested it on windows (CL) and linux (GCC).
To compile it with gcc I used gcc TclSH.c -o TclSHI -ltcl8.6
On windows I used Visual Studio.
It tells Tcl that it did not receive any arguments (Tcl_Main(1,...)), but populates the new interp with this arguments and sources the file. After this step it will always show the prompt (it never received any arguments, right?).
There is a small problem with your expect solution, if you specify any arguments, Tcl would execute that script, and never show the prompt.
Also note that I'm a novice C programmer, so this solution might not be bullet proof.
What you want to do is to wait for an unambiguous marker that indicates that the subordinate process is ready.
# ... your script as above ...
expect "% "
#### NEW STUFF STARTS ####
send "reload;puts READY\r"
expect "READY\r"
# Note that we need to fake the prompt; c'est la vie
send_user "\nUse 'reload' procedure to re-source utility files\n\n% "
# Now start doing things!
log_user 1
interact
Or at least that works when I try with a subordinate process, but I wasn't using rlwrap in the mix so that might change things…
Related
I am trying to learn about AFL-fuzzer and I have some questions:
I saw a video shows that if for instance there are two inputs in the code, so in the test case each line is for each input. Is that correct? Since I want put a full message (for example HTTP request) into one variable, so how do I do it?
I don't understand when to put ##.
For example I am trying to fuzz this code:
void Check_buffer(char* data)
{
char buffer[5];
strcpy(buffer, data);
}
int main(int argc, char* argv[])
{
char tmp_data = argv[1];
Check_buffer(argv[1]);
return 0;
}
I have created the in and out folders. In the in folder I have created a txt file with this content: "AAA".
The command line I have executed is:afl-clang -fno-stack-protector -z execstack 4.c -o vul4
Then I run:afl-fuzz -m none -i in/ -o out/ ./vul4 ##
I get the following error:perform_dry_run(), afl-fuzz.c:2852
If I run the command like this:afl-fuzz -m none -i in/ -o out/ ./vul4 AA
it runs good but it does not find any new path and does not find crashes.
As well as, I am trying to understand the concepts of this. If I want to inject code in specific location, how do I do it?
You are trying to get data from command line arguments, but the AFL does not work with argv[] (unless your program reads files like ./prog file.txt ).
Instead use something like
#define INPUTSIZE 100
char input[INPUTSIZE] = {0};
read (STDIN_FILENO, input, INPUTSIZE)
If you are still interested in getting data from argv[], you can use the experimental method from the AFL repository afl argv experimental
## is used when your program accepts a file via the command line
this means that the fuzzer will take the file, mutate it, and substitute it into the program instead ##
p.s.
#include <stdio.h>
#include <unistd.h>
#define INPUTSIZE 100
void Check_buffer(char* data)
{
char buffer[5];
strcpy(buffer, data);
}
int main(int argc, char* argv[])
{
char input[INPUTSIZE] = {0};
read (STDIN_FILENO, input, INPUTSIZE);
Check_buffer(input);
return 0;
}
AFL result image
Suppose a tool X need to developed which are written in C/C++ and having Tcl commanline interface, what will the steps or way?
I know about Tcl C API which can be used to extend Tcl by writing C extension for it.
What you're looking to do is embedding Tcl (totally a supported use case; Tcl remembers that it is a C library) but still making something tclsh-like. The simplest way of doing this is:
Grab a copy of tclAppInit.c (e.g., this is the current one in the Tcl 8.6 source tree as I write this) and adapt it, probably by putting the code to register your extra commands, linked variables, etc. in the Tcl_AppInit() function; you can probably trim a bunch of stuff out simply enough. Then build and link directly against the Tcl library (without stubs) to get effectively your own custom tclsh with your extra functionality.
You can use Tcl's API more extensively than that if you're not interested in interactive use. The core for non-interactive use is:
// IMPORTANT: Initialises the Tcl library internals!
Tcl_FindExecutable(argv[0]);
Tcl_Interp *interp = Tcl_CreateInterp();
// Register your custom stuff here
int code = Tcl_Eval(interp, "your script");
// Or Tcl_EvalFile(interp, "yourScriptFile.tcl");
const char *result = Tcl_GetStringResult(interp);
if (code == TCL_ERROR) {
// Really good idea to print out error messages
fprintf(stderr, "ERROR: %s\n", result);
// Probably a good idea to print error traces too; easier from in Tcl
Tcl_Eval(interp, "puts stderr $errorInfo");
exit(1);
}
// Print a non-empty result
if (result[0]) {
printf("%s\n", result);
}
That's about all you need unless you're doing interactive use, and that's when Tcl_Main() becomes really useful (it handles quite a few extra fiddly details), which the sample tclAppInit.c (mentioned above) shows how to use.
Usually, SWIG (Simplified Wrapper and Interface Generator) is the way to go.
SWIG HOMEPAGE
This way, you can write code in C/C++ and define which interface you want to expose.
suppose you have some C functions you want added to Tcl:
/* File : example.c */
#include <time.h>
double My_variable = 3.0;
int fact(int n) {
if (n <= 1) return 1;
else return n*fact(n-1);
}
int my_mod(int x, int y) {
return (x%y);
}
char *get_time()
{
time_t ltime;
time(<ime);
return ctime(<ime);
}
Now, in order to add these files to your favorite language, you need to write an "interface file" which is the input to SWIG. An interface file for these C functions might look like this :
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
At the UNIX prompt, type the following:
unix % swig -tcl example.i
unix % gcc -fpic -c example.c example_wrap.c \
-I/usr/local/include
unix % gcc -shared example.o example_wrap.o -o example.so
unix % tclsh
% load ./example.so example
% puts $My_variable
3.0
% fact 5
120
% my_mod 7 3
1
% get_time
Sun Feb 11 23:01:07 2018
The swig command produces a file example_wrap.c that should be compiled and linked with the rest of the program. In this case, we have built a dynamically loadable extension that can be loaded into the Tcl interpreter using the 'load' command.
Taken from http://www.swig.org/tutorial.html
I am working on app which uses tcl package implemented in C++ and linked as static library (app is developed long time ago). It does following:
// Library code
extern "C" int testlib_SafeInit _ANSI_ARGS_((Tcl_Interp *interp))
{
return Tcl_PkgProvide(interp, "testlib", "1.6");
}
extern "C" int testlib_Init _ANSI_ARGS_((Tcl_Interp *interp))
{
return testlib_SafeInit(interp);
}
// Application code
extern "C" int testlib_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
extern "C" int testlib_Init _ANSI_ARGS_((Tcl_Interp *interp));
int main()
{
Tcl_Interp* interp = Tcl_CreateInterp();
Tcl_Init(interp);
Tcl_PkgProvide(interp, "testlib", "1.6");
Tcl_StaticPackage(interp, "testlib", testlib_Init, testlib_SafeInit);
Tcl_Eval(interp, "package require testlib");
std::cout << "Res = " << Tcl_GetStringResult(interp);
return 0;
}
When I am removing line Tcl_PkgProvide(interp, "testlib", "1.6"); from main, package becomes invisible. Also I have noticed that testlib_Init and testlib_SafeInit are not called. I am expecting that they must be called from package require testlib. As I understand from docs each package must have pkgIndex.tcl in auto_path or tcl_pkgPath which must contain line
(package ifneeded testlib 1.6 {load {} testlib}), but here both variables does not contain such index file.
Is this a correct way of providing packages? Is there a documentation related with providing packages using static libraries?
Well, the simplest technique for statically providing a package is to just install it directly. The package init code should be the one calling Tcl_PkgProvide — you don't do so from main() usually — and you probably don't need Tcl_StaticPackage at all unless you're wanting to install the code into sub-interpreters.
int main(int argc, char*argv[])
{
Tcl_FindExecutable(argv[0]);
Tcl_Interp* interp = Tcl_CreateInterp();
Tcl_Init(interp);
testlib_Init(interp);
// OK, setup is now done
Tcl_Eval(interp, "package require testlib");
std::cout << "Res = " << Tcl_GetStringResult(interp) << "\n";
return 0;
}
However, we can move to using Tcl_StaticPackage. That allows code to say “instead of loading a DLL with this sort of name, I already know that code: here are its entry points”. If you are doing that, you need to also install a package ifneeded script; those are done through the script API only.
int main(int argc, char*argv[])
{
Tcl_FindExecutable(argv[0]);
Tcl_Interp* interp = Tcl_CreateInterp();
Tcl_Init(interp);
Tcl_StaticPackage(interp, "testlib", testlib_Init, testlib_SafeInit);
Tcl_Eval(interp, "package ifneeded testlib 1.6 {load {} testlib}");
// OK, setup is now done
Tcl_Eval(interp, "package require testlib");
std::cout << "Res = " << Tcl_GetStringResult(interp) << "\n";
return 0;
}
The testlib in the load call needs to match the testlib in the Tcl_StaticPackage call. The testlib in the package require, package ifneeded and Tcl_PkgProvide also need to all match (as do the occurrences of 1.6, the version number).
Other minor issues
Also, you don't need to use the _ANSI_ARGS_ wrapper macro. That's utterly obsolete, for really ancient and crappy compilers that we don't support any more. Just replace _ANSI_ARGS_((Tcl_Interp *interp)) with (Tcl_Interp *interp). And remember to call Tcl_FindExecutable first to initialise the static parts of the Tcl library. If you don't have argv[0] available to pass into it, use NULL instead; it affects a couple of more obscure introspection systems on some platforms, but you probably don't care about them. However, initialising the library overall is very useful: for example, it lets you make sure that the filesystem's filename encoding scheme is correctly understood! That can be a little important to code…
#include <tcl.h>
int main(int argc, char** argv)
{
Tcl_Interp *interp = Tcl_CreateInterp();
Tcl_Channel stdoutChannel = Tcl_GetChannel(interp, "stdout", NULL);
Tcl_UnregisterChannel(interp, stdoutChannel);
Tcl_Channel myChannel = Tcl_OpenFileChannel(interp, "/home/aminasya/nlb_rundir/imfile", "w", 0744);
Tcl_RegisterChannel(interp, myChannel);
Tcl_Eval(interp, "puts hello");
}
In this code I have tried to close stdout channel and redirect it to file. (As described Get the output from Tcl C Procedures). After running, "imfile" is created but empty. What am doing wrong?
I have seen How can I redirect stdout into a file in tcl too, but I need to do it using Tcl C API.
I have also tried this way, but again no result.
FILE *myfile = fopen("myfile", "W+");
Tcl_Interp *interp = Tcl_CreateInterp();
Tcl_Channel myChannel = Tcl_MakeFileChannel(myfile, TCL_WRITABLE);
Tcl_SetStdChannel(myChannel, TCL_STDOUT);
The difficulty in your case is the interaction between the standard channels of a Tcl interpreter and the file descriptors (FDs) of the standard streams as seen by the main program (and the C runtime), coupled with the semantics of open(2) in Unix.
The process which makes all your output redirected rolls like this:
The OS makes sure the three standard file descriptors (FDs) are open (and numbered 0, 1 and 2, with 1 being the standard output) by the time the program starts executing.
As soon as the Tcl interpreter you create initializes its three standard channels (this happens when you call Tcl_GetChannel() for "stdout", as described here), they get associated with those already existing three FDs in the main program.
Note that the underlying FDs are not cloned, instead, they are just "borrowed" from the enclosing program. In fact, I think in 99% of cases this is a sensible thing to do.
When you close (which happend when unregisteting) the standard channel stdout in your Tcl interpreter, the underlying FD (1) is closed as well.
The call to fopen(3) internally calls open(2) which picks up the lowest free FD, which is 1, and thus the standard output stream as understood by the main program (and the C runtime) is now connected to that opened file.
You then create a Tcl channel out of your file and register it with the interpreter. The channel indeed becomes stdout for the interpreter.
In the end, both writes to the standard output stream in your main program and writes to the standard output channel in your Tcl interpreter are sent do the same underlying FD and hence end up in the same file.
I can see two ways to deal with this behaviour:
Play a neat trick to "reconnect" the FD 1 to the same stream it was initially opened to and make the file opened for the Tcl interpreter's stdout use an FD greater than 2.
Instead of first letting the Tcl interpreter initialize its standard channels and then reinitializing one of them, initialize them all manually before letting that auto-vivification machinery kick in.
Both approaches have their pros and cons:
"Preserving FD 1" is generally simpler to implement, and if you want to redirect only stdout in your Tcl interpreter, and leave the two other standard channels to be connected to the same standard streams used by the enclosing program, this approach seems to be sensible to employ. The possible downsides are:
Too much magic involved (extensive commenting the code is advised).
Not sure how this would work on Windows: there's no dup(2) there (see below) and some other approach might be needed.
Not using the standard streams for stdin and stderr from the enclosing program might be useful.
Initializing the standard channels in the Tcl interpreter by hand requires more code and supposedly warrants the correct ordering (stdin, stdout, stderr, in that order). If you want the remaining two standard channels in your Tcl interpreter to be connected to the matching streams of the enclosing program, this approach is more work; the first approach does this for free.
Here's how to preserve FD 1 to make only stdout in the Tcl interpreter be connected to a file; for the enclosing program FD 1 is still connected to the same stream as set up by the OS.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tcl.h>
int redirect(Tcl_Interp *interp)
{
Tcl_Channel chan;
int rc;
int fd;
/* Get the channel bound to stdout.
* Initialize the standard channels as a byproduct
* if this wasn't already done. */
chan = Tcl_GetChannel(interp, "stdout", NULL);
if (chan == NULL) {
return TCL_ERROR;
}
/* Duplicate the descriptor used for stdout. */
fd = dup(1);
if (fd == -1) {
perror("Failed to duplicate stdout");
return TCL_ERROR;
}
/* Close stdout channel.
* As a byproduct, this closes the FD 1, we've just cloned. */
rc = Tcl_UnregisterChannel(interp, chan);
if (rc != TCL_OK)
return rc;
/* Duplicate our saved stdout descriptor back.
* dup() semantics are such that if it doesn't fail,
* we get FD 1 back. */
rc = dup(fd);
if (rc == -1) {
perror("Failed to reopen stdout");
return TCL_ERROR;
}
/* Get rid of the cloned FD. */
rc = close(fd);
if (rc == -1) {
perror("Failed to close the cloned FD");
return TCL_ERROR;
}
/* Open a file for writing and create a channel
* out of it. As FD 1 is occupied, this FD won't become
* stdout for the C code. */
chan = Tcl_OpenFileChannel(interp, "aaa.txt", "w", 0666);
if (chan == NULL)
return TCL_ERROR;
/* Since stdout channel does not exist in the interp,
* this call will make our file channel the new stdout. */
Tcl_RegisterChannel(interp, chan);
return TCL_OK;
}
int main(void)
{
Tcl_Interp *interp;
int rc;
interp = Tcl_CreateInterp();
rc = redirect(interp);
if (rc != TCL_OK) {
fputs("Failed to redirect stdout", stderr);
return 1;
}
puts("before");
rc = Tcl_Eval(interp, "puts stdout test");
if (rc != TCL_OK) {
fputs("Failed to eval", stderr);
return 2;
}
puts("after");
Tcl_Finalize();
return 0;
}
Building and running (done in Debian Wheezy):
$ gcc -W -Wall -I/usr/include/tcl8.5 -L/usr/lib/tcl8.5 -ltcl main.c
$ ./a.out
before
after
$ cat aaa.txt
test
As you can see, the string "test" output by puts goes to the file while the strings "before" and "after", which are write(2)n to FD 1 in the enclosing program (this is what puts(3) does in the end) go to the terminal.
The hand-initialization approach would be something like this (sort of pseudocode):
Tcl_Channel stdin, stdout, stderr;
stdin = Tcl_OpenFileChannel(interp, "/dev/null", "r", 0666);
stdout = Tcl_OpenFileChannel(interp, "aaa.txt", "w", 0666);
stderr = Tcl_OpenFileChannel(interp, "/dev/null", "w", 0666);
Tcl_RegisterChannel(interp, stdin);
Tcl_RegisterChannel(interp, stdout);
Tcl_RegisterChannel(interp, stderr);
I have not tested this approach though.
At the level of the C API, and assuming that you are on a Unix-based OS (i.e., not Windows), you can do this far more simply by using the right OS calls:
#include <fcntl.h>
#include <unistd.h>
// ... now inside a function
int fd = open("/home/aminasya/nlb_rundir/imfile", O_WRONLY|O_CREAT, 0744);
// Important: deal with errors here!
dup2(fd, STDOUT_FILENO);
close(fd);
You could also use dup() to save the old stdout (to an arbitrary number that Tcl will just ignore) so that you can restore it later, if desired.
Try this:
FILE *myfile = fopen("myfile", "W+");
Tcl_Interp *interp = Tcl_CreateInterp();
Tcl_Channel myChannel = Tcl_MakeFileChannel(myfile, TCL_WRITABLE);
Tcl_RegisterChannel(myChannel);
Tcl_SetStdChannel(myChannel, TCL_STDOUT);
You need to register the channel with the interpreter before you can reset the std channel to use it.
I'm currently wrapping a command line tool (espeak) with Tcl/Tk, and I have figured this out so far:
load ./extensions/system.so
package require Tk
package require Tclx
set chid 0
proc kill {id} {
exec kill -9 $id
}
proc speak {} {
global chid
set chid [fork]
if {$chid == 0} {
execvp espeak [.text get 1.0 end]
}
}
proc silent {} {
global chid
kill $chid
}
Where system.so is an extension I hacked together to be able to use execvp:
#include <tcl.h>
#include <tclExtend.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static int
execvp_command(ClientData cdata, Tcl_Interp *interp, int argc, const char* argv[])
{
if (argc == 1)
{
interp->result = "execvp command ?args ...?";
return TCL_ERROR;
}
execvp(argv[1], argv + 1);
return TCL_OK;
}
int System_Init(Tcl_Interp* interp)
{
if (Tcl_InitStubs(interp, "8.1", 0) == NULL)
return TCL_ERROR;
Tcl_CreateCommand(interp, "execvp", execvp_command, NULL, NULL);
Tcl_PkgProvide(interp, "system", "1.0");
return TCL_OK;
}
The reason I need execvp is because a subprocess created by exec (Tcl) seems to keep going when the process dies (I can confirm this by ^C'ing out of the GUI), whereas if I use execvp, espeak dies properly.
Thus, all I really need out of this script is to be able to start a subprocess and kill it on demand.
Is there another library that can do this properly, like Expect?
Tcl uses execvp internally (really; I've just checked the source) so the difference lies elsewhere. That elsewhere will be in signals; the subprocess created by the exec command (and other things that use the same underlying engine) will have the majority of signals forced to use the default signal handlers, but since the only signal it sets to non-default is SIGPIPE, I wonder what else is going on.
That said, the definitive extension for working with this sort of thing is TclX. That gives you access to all the low-level POSIX functionality that you've been using partially. (Expect may also be able to do it.)