I have written a code where in it would take in a executable file and the [lib*.so] library as my arguments and link # Run-time.
I want to also take in the function in the (*.o) file # run-time and link it.
But I don't know how to go about it.
EDIT 1:
The function I'm trying to link is a part of the .o file in the lib*.so library.
So I want to specify the library name and also the function name which is in the same library # Run-Time.
For eg. If my library contains two functions(i.e *.o files) the linker should compile the function which I want to use #Run-Time.
I have posted the code,please help :
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h> // use -ldl
typedef float (*DepFn)(short, short);
int main(int argc, char* argv[])
{
void* lib;
DepFn df;
if(argc < 2)
return printf("USAGE: %s lib-file\n", argv[0]);
lib = dlopen(argv[1], RTLD_NOW);
if(lib == NULL)
return printf("ERROR: Cannot load library\n");
df = dlsym(lib, "Depreciation");
if(df)
{
short l, i;
printf("Enter useful-life of asset: ");
scanf("%hd", &l);
for(i = 1; i <= l; i++)
{
float d = 100 * df(l, i);
printf("%hd\t%.1f%%\n", i, d);
}
}
else
printf("ERROR: Invalid library\n");
dlclose(lib);
}
If you need to take the function name at runtime, you need to pass it in argv[2], and instead of hardcoding function-name in the dlsym use argv[2].
if(argc < 3)
return printf("USAGE: %s lib-file function-name\n", argv[0]);
lib = dlopen(argv[1], RTLD_NOW);
if(lib == NULL)
return printf("ERROR: Cannot load library\n");
df = dlsym(lib, argv[2]);
You cannot load a relocatable (*.o) at run time using standard functions. You need to make sure the object is compiled as position independent code (e.g. -fPIC) and then make a shared object out of it. Something like ld -shared -o foo.so foo.o may do the trick.
Based on your comments, you just want to link to your shared library,
change your code to:
extern float Depreciation(short i,k); //should rather go in a header file
int main(int argc, char* argv[])
{
short l, i;
printf("Enter useful-life of asset: ");
scanf("%hd", &l);
for(i = 1; i <= l; i++)
{
float d = 100 * Depreciation(l, i);
printf("%hd\t%.1f%%\n", i, d);
}
}
Compile and link to your shared library:
gcc -o myprogram myprogram.c -lXX
Your libXX.so would need to be installed in e.g. /usr/lib/ for the above to work
See here for more info.
Related
I've several files with main functions in C, for example, I've files called show.c, delete.c add.c (...). I also have a file, called interpreter.c, which may call one of the files, for example delete.c. Most of these file implement a main function, like the delete.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int main (int argc, char *argv[])
{
int fd, rm;
char *caminho = argv[1]; // argumento inserido no terminal
char caminhod[30]="../TPSOFinal/";
strcat(caminhod,argv[1]);
fd = open(caminhod, O_RDONLY);
rm=unlink(caminhod);
// Verifica se o caminho inserido no input existe
if(rm == 0){
write(1,"Ficheiro eliminado!!!\n", 22);
return 0;
}
else{
write(1,"Erro ao eliminar ficheiro !!!\n", 29);
perror("Erro");
}
return 0;
close(fd);
}
The interpreter:
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>
#define LER_BUFFER 1024
#define TBUFF 64
#define DELIM "\t\r\n\a"
int mostra(char **args);
int conta(char **args);
int acrescenta(char **args);
int apaga(char **args);
int informa(char **args);
int lista(char **args);
int manual(char **args);
int termina(char **args);
char *comando[] =
{
"mostra <caminho>",
"conta <caminho>",
"acrescenta <caminho> <caminho destino>",
"apaga <caminho>",
"informa <caminho>",
"lista <caminho>",
"manual",
"termina",
" ",
};
int (*fcomandos[]) (char**) =
{
&mostra,
&conta,
&acrescenta,
&apaga,
&informa,
&lista,
&manual,
&termina
};
int ncomandos()
{
return sizeof(comando)/sizeof(char*);
}
void processa(char *linha, char **argv)
{
while(*linha != '\0')
{
while(*linha == ' ' || *linha == '\t' || *linha == '\n')
{
*linha++ = '\0'; //troca caracteres especiais
}
*argv++ = linha; //guarda posição
while (*linha != '\0' && *linha != ' ' && *linha != '\t' && *linha != '\n')
{
linha++;
}
}
*argv = NULL;
}
char *lerlinha (void)
{
char *linha = NULL;
ssize_t tam = 0;
getline (&linha, &tam, stdin);
return linha;
}
char **separa (char *linha)
{
int tam = TBUFF, pos = 0;
char **palavras = malloc (tam *sizeof(char*));
char *palavra;
if (!palavras)
{
perror("Erro");
exit(EXIT_FAILURE);
}
palavra = strtok (linha, DELIM);
while (palavra != NULL)
{
palavras [pos] = palavra;
pos ++;
if (pos >= tam)
{
perror ("Erro");
}
}
palavra = strtok(NULL, DELIM);
palavras [pos] = NULL;
return palavras;
}
int launch (char **args)
{
pid_t pid, wpid;
int estado;
pid = fork();
if (pid == 0)
{
if(execvp(args[0],args)==-1){ perror ("Erro!"); }
exit (EXIT_FAILURE);
}
if (pid <0)
{
perror ("Erro!");
}
else
{
do{wpid = waitpid(pid, &estado, WUNTRACED);}
while (!WIFEXITED(estado)&& !WIFSIGNALED(estado));
}
return 1;
}
//Testa se os comandos existem
int mostra (char **args)
{
if (args[1] == NULL)
{
perror("sem argumentos ");
}
else if (chdir (args[1]) != 0)
{
perror ("Erro!");
}
return 1;
}
int conta ( char ** args)
{
if (args[1] == NULL)
{
perror("Sem argumentos ");
}
else if (chdir (args[1])!= 0)
{
perror ("Erro!");
}
return 1;
}
// Manual dos comandos
int manual (char **args)
{
int i;
printf("\n\nMiguel Oliveira\n");
printf("10260 - LESI\n");
printf("Sistemas Operativos e Sistemas Distribuidos\n");
printf("\nLista de Comandos\n");
for (i=0; i<ncomandos(); i++)
{
printf("%s\n", comando[i]);
}
return 1;
}
int termina (char **args)
{
return 0;
}
//Executa os comandos
int executar (char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i=0; i<ncomandos(); i++)
{
if (strcmp(args[0], comando[i])==0)
{
return (*fcomandos[i])(args);
}
}
return launch(args);
}
//Interpretador
void interpretador (void)
{
char *linha;
char **args;
int estado;
do
{
printf("%% ");
linha = lerlinha();
args = separa(linha);
estado = executar(args);
free(linha);
free(args);
} while (estado);
}
int main (void)
{
interpretador();
return EXIT_SUCCESS;
}
I've tried to research for similar problems, and i've found some little possible solutions, but cannot solve my problem, as show on bottom GCC compile mistake
You do not "call source files"; source files define functions and variables, and when compiled, ones defined in different files can use each other if they have a declaration (in a header file, usually) or a pointer (via dynamic link methods, like POSIX dlsym()).
Consider this minimal example. First, example.c:
#include <stdlib.h>
#include <stdio.h>
/* We expect someone else to define these */
extern int one(void);
int main(void)
{
printf("one() returned %d.\n", one());
return EXIT_SUCCESS;
}
and helper.c:
int one(void)
{
return 2; /* TODO: It's not one! */
}
You compile each source file to an object file:
gcc -Wall -O2 -c example.c
gcc -Wall -O2 -c helper.c
and then you link them to an executable program:
gcc -Wall -O2 example.o helper.o -o program
which you can run using
./program
Normally, each C source file that provides functions or variables usable outside that file, declares them in a header file. Here's a better example.
degrees.h
#ifndef DEGREES_H
#define DEGREES_H
double radians_to_degrees(double);
double degrees_to_radians(double);
#endif /* DEGREES_H */
The #ifndef, #define, and #endif are used as guards, so that if you #include the file more than once, the functions get declared only once. (The compiler will complain if it sees multiple declarations. Plus, we don't need to use extern here.)
The implementation of the above is then in degrees.c,
#ifndef PI
#define PI 3.14159265358979323846
#endif
double degrees_to_radians(double degrees)
{
return degrees * PI / 180.0;
}
double radians_to_degrees(double radians)
{
return radians * 180.0 / PI;
}
In a program myprog.c in the same project, you would use the above thus:
#include <stdlib.h>
#include <stdio.h>
#include "degrees.h"
int main(void)
{
printf("45 degrees is %.6f radians.\n", degrees_to_radians(45.0));
printf("2 radians is %.3f degrees.\n", radians_to_degrees(2.0));
return EXIT_SUCCESS;
}
and again you'd compile first the two source files to object files,
gcc -Wall -O2 -c degrees.c
gcc -Wall -O2 -c myprog.c
and then link together to a program, say myprog,
gcc -Wall -O2 degrees.o myprog.o -o myprog
which you can then run:
./myprog
It is also possible to compile and link the functions and variables declared in degrees.h to a static (libdegrees.a) or a dynamic (libdegrees.so) library, and install the header file to the standard location, so that your program could instead use #include <degrees.h> and the program link to the library via -ldegrees, but that is better left until you are well comfortable working with multiple files.
Until then, you might find the following Makefile useful
CC := gcc
CFLAGS := -Wall -O2
LDFLAGS :=
PROGS := myprog
all: clean $(PROGS)
clean:
rm -f *.o $(PROGS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
myprog: degrees.o myprog.o
$(CC) $(CFLAGS) $^ -o $#
You can add multiple programs in the PROGS line, separated by spaces, and copy the myprog: lines for each, listing the object files that program needs.
With this, all you need to compile the program is to type make.
This forum eats Tabs, and Makefiles need indentation to use those. So, if you just copy-paste that to a file, it won't work. You can fix it, though, by running
sed -e 's|^ *|\t|' -i Makefile
which removes all initial spaces on each line with a tab in file Makefile.
If you use separate libraries, typically libm (#include <math.h>), you just need to add -lm (dash ell em) to the LDFLAGS line. If you eventually play with dynamic linking, that's -ldl.
If you were to write a graphical program using Gtk+, you'd append `pkg-config --cflags gtk+-3.0` (including the backticks `) to the CFLAGS line, and `pkg-config --libs gtk+-3.0` to the LDFLAGS line, and #include <gtk/gtk.h> to your program.
For compilation I used:
1) ./configure --enable-dddmp --enable-obj --enable-shared --enable-static; make
2) gcc test.c -o testprogram -I /path/to/cudd-3.0.0/cudd -I /path/to/cudd-3.0.0/util -I /path/to/cudd-3.0.0/ -static -L /path/to/cudd-3.0.0/cudd/.libs/ -lcudd -lm
The program is compiled successfully. I am using cudd3.0.0 package. After that I am getting this segmentation error in execution:
Please suggest the proper way to execute this and why I am getting this error?
I am adding the main function:
int main (int argc, char *argv[])
{
char filename[30];
DdManager *gbm; /* Global BDD manager. */
gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
DdNode *bdd, *var, *tmp_neg, *tmp;
int i;
bdd = Cudd_ReadOne(gbm); /*Returns the logic one constant of the manager*/
Cudd_Ref(bdd); /*Increases the reference count of a node*/
for (i = 3; i >= 0; i--) {
var = Cudd_bddIthVar(gbm,i); /*Create a new BDD variable*/
tmp_neg = Cudd_Not(var); /*Perform NOT boolean operation*/
tmp = Cudd_bddAnd(gbm, tmp_neg, bdd); /*Perform AND boolean operation*/
Cudd_Ref(tmp);
Cudd_RecursiveDeref(gbm,bdd);
bdd = tmp;
}
bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
print_dd (gbm, bdd, 2,4); /*Print the dd to standard output*/
sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
write_dd(gbm, bdd, filename); /*Write the resulting cascade dd to a file*/
Cudd_Quit(gbm);
return 0;
}
Yes, It is resolved. I have not made the folder named 'bdd' in the proper location for the code line:
sprintf(filename, "./bdd/graph.dot");
Now, it is executing. Sorry, I thought it was some conceptual error.
I have a handful of shared libraries with cyclic dependencies, which I want to load with dlopen. To do this, I call dlopen with the RTLD_LAZY | RTLD_GLOBAL flags.
This works fine.
Now, I want to check that all symbols in all shared libraries are fully resolved, and I therefore call dlopen again with RTLD_NOW, this should fail if all symbols can not be resolved.
At least, this is how I understand the man page:
However, a subsequent dlopen() call that loads the same shared object with
RTLD_NOW may force symbol resolution for a shared object earlier loaded with
RTLD_LAZY.
Here is a simple example which illustrates my problem:
main.h
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "h.h"
#define CNT 3
static const char *libs[CNT] = {"./liba.so", "./libb.so", "./libc.so"};
typedef int (*f_ptr)();
int main() {
void *h[CNT];
f_ptr f[CNT];
for (int i = 0; i < CNT; i++) {
printf("dlopen: %s\n", libs[i]);
h[i] = dlopen(libs[i], RTLD_LAZY | RTLD_GLOBAL);
if (!h[i]) {
fprintf(stderr, "%d %s: %s\n", __LINE__, libs[i], dlerror());
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < CNT; i++) {
printf("dlopen again: %s\n", libs[i]);
void *xx = dlopen(libs[i], RTLD_NOW | RTLD_GLOBAL);
if (!xx) {
fprintf(stderr, "%d %s: %s\n", __LINE__, libs[i], dlerror());
dlclose(h[i]);
h[i] = 0;
} else {
dlclose(xx);
}
}
for (int i = 0; i < CNT; i++) {
if (h[i]) {
f[i] = (int (*)())dlsym(h[i], "init");
if (!f[i]) {
fprintf(stderr, "%d %s: %s\n", __LINE__, libs[i], dlerror());
exit(EXIT_FAILURE);
}
}
}
for (int i = 0; i < CNT; i++) {
if (f[i]) {
printf("%s %08d\n", libs[i], f[i]());
}
}
return 0;
}
a.c
#include "h.h"
int init() { return 1 + b_(); }
int a_() { return 10; }
b.c
#include "h.h"
int init() { return 100 + a_(); }
int b_() { return 1000; }
c.c
#include "h.h"
int init() { return 10000 + x_(); }
int c_() { return 100000; }
h.h
int init();
int a_();
int b_();
int x_();
CMakeLists.txt
project(xx)
add_library(a SHARED a.c)
add_library(b SHARED b.c)
add_library(c SHARED c.c)
add_executable(main main.c)
target_link_libraries(main dl)
Compile and run:
$ mkdir b && cd b && cmake .. && make && ./main
...
[100%] Built target b
dlopen: ./liba.so
dlopen: ./libb.so
dlopen: ./libc.so
dlopen again: ./liba.so
dlopen again: ./libb.so
dlopen again: ./libc.so
./liba.so 00001001
./libb.so 00000110
./main: symbol lookup error: ./libc.so: undefined symbol: x_
How can I detect that libc.so could not be fully loaded - before calling a
symbol that cause it to crash?
Ideally you'd want to put the burden of symbol cross-matching on static linker as suggested by others (via --no-allow-shlib-undefined) rather than delaying it to startup. Now it's a bit complicated for cyclic dependencies but Solaris (of which Linux shlibs are a bleak copy) has come with a clever solution - shlib filters. The idea is that you link against dummy shlibs which export equally dummy symbols and have the same sonames as final production libraries. These are of course only used at link time to verify dependencies.
As a side note, I'm pretty sure that generation of dummy libs can be automated, something like the following:
build lib without --no-allow-shlib-undefined
use readelf or whatever to extract exported symbols
generate a dummy C (or asm) file which defines empty stubs for symbols from previous item
build lib and voila - you've built your first filter
Hm, this sounds like a nice mini-project for this evening.
I can't solve the error: undefined reference to lire in function main in proj.c.
collect2: error ld returned 1 exit status
Question structure
Details of question
Code for main functions - allouer (=allocate) and lire (=read) (file is called allocate_plat.c)
proj.c source file - should take filename as argument and read it using function lire
proj.h header file - structure definitions and prototype functions
Makefile - I can't believe this causes the problem but included for completeness
Example txt file to read. For information only
1.This is my first at using multiple source files - the goal is to open a game board for a game like this: http://www.rci-jeux.com/jeux/labychiffres/laby.swf .
I am studying abroad, and have some trouble in technical discussions with the lecturer, and think my understanding of pointers or at least when and where to use * and & is weak - I have already spent some time trying to get the game file passed from the command line of proj.c to allocate_plat.c - I believe this works, but if you spot a mistake please point it out. Code follows - have had guidance for the structures so am confident they are appropriate.
What I have tried - the current situation is the culmination of a few hours ironing out (I hope) bugs with passing the filename argument from proj.c to allocate_plat.c This is the first time I have seen this type of error,and I am not sure where to start.
I have read C++ Undefined reference to function implemented and templated in code and can't see the solution.
2.allocate_plat.c to allocate space and then read the game data (this is by analogy with a matrix data structure used in a weekly assignment, and we have been told we can largely copy that, so it should work, (though for that I only used one source file.)
#include <stdio.h>
#include <stdlib.h>
#include "proj.h"
int allouer(PLATEAU *PLAT, int nl, int nc, int ldep, int cdep, int larr, int carr, int longdem, int sumdem){
int i,succes;
PLAT->grille = (int**)calloc(nl,sizeof(int*));
PLAT->nl = nl;
PLAT->nc = nc;
PLAT->longdem = longdem;
PLAT->sumdem = sumdem;
PLAT->dep.indl = ldep;
PLAT->dep.indc = cdep;
PLAT->arr.indl = larr;
PLAT->arr.indc = carr;
succes = (PLAT->grille != NULL);
for (i=0; succes && i<nl;i++){
PLAT->grille[i]=(int*)calloc(nc,sizeof(int));
succes = (PLAT->grille[i] != NULL);
}
return succes;
}
int lire(char *nom_fichier, PLATEAU *PLAT){
int i,j,succes, c;
PLATEAU jeu;
FILE *fp;
fp = fopen(nom_fichier, "rt");
if(fp==NULL) {
printf("Erreur d'ouverture du fichier\n");
return 0;
}
c = fscanf(fp,"%d %d",&PLAT->nl,&PLAT->nc);//Read first line
if( c != 2){
printf("Erreur de format de fichier\n");
fclose(fp);
return 0;
}
c = fscanf(fp,"%d %d",&PLAT->dep.indl,&PLAT->dep.indc);//Read second line
if( c != 2){
printf("Erreur de format de fichier\n");
fclose(fp);
return 0;
}
c = fscanf(fp,"%d %d",&PLAT->arr.indl,&PLAT->arr.indc);//Read third line
if( c != 2){
printf("Erreur de format de fichier\n");
fclose(fp);
return 0;
}
c = fscanf(fp,"%d %d",&PLAT->longdem,&PLAT->sumdem);//Read fourth line
if( c != 2){
printf("Erreur de format de fichier\n");
fclose(fp);
return 0;
}
//ALLOCATE THE FILE TO THE STRUCT
succes = allouer(PLAT, PLAT->nl, PLAT->nc, PLAT->dep.indl, PLAT->dep.indc, PLAT->arr.indl, PLAT->arr.indc, PLAT->longdem, PLAT->sumdem );
if(succes==0) {
printf("Erreur d'allocation\n");
fclose(fp);
return 0;
}
for(i=0; i< PLAT->nl; i++){
for(j=0; j<PLAT->nc; j++){
c=fscanf(fp, "%d", &PLAT->grille[i][j]);
if(c != 1){
printf("Erreur de format de fichier\n");
fclose(fp);
return 0;
}
}
}
fclose(fp);
return 1;
}
3.Main source file: proj.c
#include <stdio.h>
#include <stdlib.h>
#include "proj.h"
int main(int argc, char* argv[]){
// char nom_fichier[25];
int choix, choix2, succes;
PLATEAU jeu;
if (argc > 1){
char *nom_fichier = argv[1];
lire(nom_fichier, &jeu);
}
return 0;
}
4.My header file: proj.h
#pragma once
typedef struct position_st{//position st is tag for the type: "struct posiition_st"
int indl;//indice of ligne
int indc;//indice of colonne
}POSITION;
typedef struct element_st{
POSITION valeur;
struct element_st *P_suivant;
}ELEMENT;
typedef struct pile_st{
ELEMENT * P_sommet;
} PILE;
//##########PLATEAU STRUCTURE DEFINITION##############
typedef struct plat_st{
//########## INFORMATION INCLUDED IN THE GAME FILES ###################
POSITION dep;//start position
POSITION arr;//finishing position
int longdem;//length of path requested
int sumdem;//total demanded
int nl;//number of rows in grille
int nc;//number of columns in grille
int ** grille;//Playing table
//########## PART TO DO WITH THE CURRENT GAME ###################
int longcur;//current length
int sumcur;//current total
PILE chemin;//the path
}PLATEAU;
//########## FUNCTION PROTOTYPES ########################
//allouer allocates the variables for the game
int allouer(PLATEAU *, int, int, int, int, int, int, int, int);
//lire reads a game from a file
int lire(char *, PLATEAU *);
5.My makefile:
CC = gcc
CFLAGS = -I #-Wall
DEPS = proj.h
OBJ = proj.o allocate_plat.o
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
proj: $(OBJ)
gcc $(CFLAGS) -o $# $^
6.Example of the file structure (probably not needed comments would not be in it)
4 4// number of orws and columns in board
1 1//starting coordinates (based at 1)
4 4//ending coordinates (based at 1)
11 96//path length and sum of elements of path required
10 13 2 5//board grid
3 15 9 4
8 6 11 14
7 12 1 16
The error is in the Makefile. With
CFLAGS = -I #-Wall
later
$(CC) $(CFLAGS) -c -o $# $<
will become
gcc -I -c -o proj.o proj.c
...where -c is interpreted as a directory (argument to -I). Did you mean
CFLAGS = -I . #-Wall
?
I've got an library which must read data from sqlite database by calling
extern int read(char** argv, int argc); // from header
it must process:
int read(char** argv, int argc) {
char* lineborder1;
char* lineborder2;
char* spaces1;
char* spaces2;
int maxl2 = 0, maxl1 = 0;
int i, maxi1, maxi2;
if (prelude() == -1) return -1;
// etc...
where prelude is inner procedure for sqlite connection:
int prelude() {
timefile = 0;
f = NULL;
#ifndef WIN32
char* temp = (char*)calloc(200, sizeof(char));
#endif
queries = (char**)malloc(sizeof(char*) * q_cnt);
for (x = 0; x < q_cnt; x++) {
queries[x] = (char*)malloc(sizeof(char) * q_size);
}
#ifdef WIN32
retval = sqlite3_open("todo.db3", &handle);
#else
home = (char*)getenv("HOME");
strcpy(temp, home);
retval = sqlite3_open(strcat(temp, "/.todo.db3"), &handle);
free(temp);
#endif
if (retval) {
printf("Database connection failed\n\r");
return -1;
}
return 0;
}
whole source is here : bitbucket: ctodo.c
I call this read from my application:
else if ((strcmp(argv[1], "read") == 0) || (strcmp(argv[1], "r") == 0)) {
return read(argv, argc);
but getting infinity cycle of this read call:
>>./todo r
Database connection failed
Database connection failed
Database connection failed
.... etc
here is how do I build it:
gcc -I . -c -o todo.a ctodo.c -lsqlite3 -O3
gcc -I . -o todo cctodo.c -lsqlite3 -O3 todo.a
help or version calls wrok fine and read works fine on windows, something specific to my linux build is here but I can't find a bug so far. what could call this read to run in infinity cycle like that?
The read function is defined in libc.so, and used to, you know, read data.
It is exceedingly likely that sqlite3_open() calls it.
By introducing your own function called read(), you've made your program enter infinite loop. If you wait long enough, your program will run out of stack and crash.
Doctor, it hurts when I do that. Well, don't do that :-)