22
Oct
2013

Configure Eclipse CDT with symbol and include path resolution (Linux GCC toolchain)

After installing Eclipse CDT (Eclipse for C/C++ development) and G++ (GCC for C++) in my Linux Mint distro, I discovered that symbol and include path resolution for C++ couldn’t be done using the Linux GCC toolchain. Although the program was compiling perfectly, the Eclipse analyzer showed everything as missing in the GUI. It was pretty strange because I noticed that manually adding the symbols and include paths to the project (through the project settings) resolved the problem, but the default C++ project using Cross GCC toolchain didn’t need this to be okay.

After looking-at and trying every single-option in the Eclipse preferences, I came to the solution. I’d like to share it because I didn’t find much useful information using Google.

Go to Window -> Preferences -> C/C++ -> New C/C++ Project Wizard -> Makefile Project -> Discovery Options. In the Discovery profile scope dropdown menu select the option Per language. Select GNU C++ in Tools and check the option Automate discovery of paths and symbols.

Now, include paths and symbols are added as part of the CDT GCC built-in Compiler Settings, for the GNU C++ language.

13
Apr
2013

C++11 Ping-Pong std::threads

Como Tarea 1 de programación en el curso Pattern-Oriented Architectures for Concurrent and Networked Software (POSA, para los amigos) que estoy haciendo en Coursera, se requirió hacer un programa sencillo de ping-pong entre threads. El objetivo era poner en práctica algunas primitivas para el manejo de la concurrencia y la sincronización. Básicamente el output por consola de este programa debía ser algo así:
Ready… Set… Go!
Ping!
Pong!
Ping!
Pong!
Ping!
Pong!
Done!

Se podían elegir muchos lenguajes para el desarrollo. Antes de pasar a lo técnico, quiero mostrar algunas cifras relativas al desarrollo del curso. Están inscriptas unas 30.000 personas apróx. Esta tarea (correspondiente a la 4ta semana del curso), fue entregada por 1.600 personas apróx. Esta fue la cantidad de programas por lenguaje:

Java 840
C++11 260
C# 199
Python 170
Ruby 56
C++ ACE 51
Scala 50
C++ boost 4


Leer el resto del artículo »

2
Nov
2012

Punteros a funciones: desde C a Assembler

En C tenemos la posibilidad de pasar punteros a funciones como parámetros de una función. Esto permite realizar llamadas a la función-parámetro desde la función. Si por ejemplo lo combinamos con parámetros de tipo *void (para la función-parámetro), podría llegar a verse como una forma rústica de polimorfismo.

Ejemplo:

#include <stdlib .h>
#include <stdio .h>
 
int foo(int);
void bar(int (*)(int));
 
int main(int argc, char *argv[]){
 
	bar(foo);
 
	return 0;
}
 
int foo(int num){
	return num;
}
 
void bar(int (*func)(int)){
	int res = (*func)(3);
	printf("res = %d\n", res);
}
</stdio></stdlib>


Leer el resto del artículo »

1
Sep
2012

Leer un archivo en C a un array de chars (char*)

En este sencillo código vamos a mostrar y comentar una técnica para leer un archivo (eventualmente binario) a un array de chars (char*) desde C, utilizando algunas system calls POSIX y alguna función de la biblioteca estándar.

/*
Auth: martin.com.uy/sec
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
 
int main(int argc, char* argv[]) {
 
	puts("Comienzo del programa...\n");
 
	int archivo_fd, archivo_open_flags;
 
	archivo_open_flags = O_RDONLY;
 
	archivo_fd = open("/ruta/al/archivo.bin", archivo_open_flags);
 
	if(archivo_fd == -1){
		puts("Error al abrir el archivo.\n");
		return EXIT_FAILURE;
	}
	puts("Archivo abierto correctamente.\n");
 
	puts("Leyendo archivo...\n");
 
	int bytes_leidos;
 
	int cantidad_bytes_archivo = 0;
 
	int comienzo_del_archivo = lseek(archivo_fd, 0, SEEK_SET);
 
	int fin_del_archivo = lseek(archivo_fd, 0, SEEK_END);
 
	printf("Comienzo del archivo offset: %d, Fin del archivo offset: %d.\n\n", comienzo_del_archivo, fin_del_archivo);
 
	cantidad_bytes_archivo = fin_del_archivo - comienzo_del_archivo;
 
	char* archivo_bytes = (char*)malloc(cantidad_bytes_archivo);
 
	lseek(archivo_fd, 0, SEEK_SET);
 
        read(archivo_fd, archivo_bytes, cantidad_bytes_archivo);
 
	printf("Lectura del archivo finalizada. Cantidad de bytes archivo: %d.\n\n", cantidad_bytes_archivo);
 
	if(close(archivo_fd) == -1){
		puts("Error al cerrar el archivo.\n");
		return EXIT_FAILURE;
	}
 
	puts("Archivo cerrado.\n");
 
	return EXIT_SUCCESS;
}

Si bien el código es auto-explicativo, quiero comentar brevemente lo que se está haciendo en la parte central de la función.

Una vez abierto el archivo (obtenido su file descriptor), el kernel almacena un offset donde se indica la posición en la que estamos parados sobre el archivo. Cada vez que utilizamos, por ejemplo, la system call read(), este offset es incrementado la cantidad de bytes que hayan sido leídos -hasta llegar al EoF-.

La system call lseek() nos permite controlar (mover) este offset donde estamos parados dentro del archivo abierto. Lo que hacemos en esta función es pararnos al principio, pararnos al final y obtener el largo del archivo en bytes. Una vez con ese largo, construimos un buffer de lectura del tamaño exacto del archivo. Con dicho buffer utilizamos la system call read() y de una sola vez cargamos el archivo.

Probablemente esta forma de leer sea más útil para archivo binarios.

30
Aug
2012

Función de Prólogo y Epílogo (lenguaje assembler)

Las funciones de Prólogo y el Epílogo son una convención (vigente para muchos lenguajes de alto nivel, como por ejemplo C) que los compiladores aplican al generar el código assembler correspondiente a una función. El objetivo es establecer una protección contra los buffer overflows.

Supongamos el siguiente código en C:

int obtener_numero_fijo();
 
int main(void) {
	return 1;
}
 
int obtener_numero_fijo(){
	return 2;
}

Luego de compilarlo (con GCC), analizamos el código objeto (con objdump) y observamos el siguiente código assembler:

00000000 
: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: b8 01 00 00 00 mov $0x1,%eax 8: 5d pop %ebp 9: c3 ret 0000000a : a: 55 push %ebp b: 89 e5 mov %esp,%ebp d: b8 02 00 00 00 mov $0x2,%eax 12: 5d pop %ebp 13: c3 ret

Podemos observar que ambas funciones comienzan poniendo el valor del registro ebp en el stack. Luego mueven el stack pointer al registro ebp. Al finalizar la función, se retira el último valor del stack y se guarda en el registro ebp.


Leer el resto del artículo »

24
Mar
2012

Crypto++: cifrar bloque binario con AES + ECB

Crypto++ es una de las bibliotecas más importantes y recomendables para implementar funciones criptográficas en C++. Es de uso libre (open source) y funciona en múltiples plataformas (Windows, Linux, OS X). Si en algún momento deciden usarla, tomenlo con paciencia porque es un poco árida al principio.

En el día de hoy comencé a implementar una demo de CTR (streamcipher) en Qt/C++. Para esta implementación -que no es tan compleja-, necesité aplicar un blockcipher a bloques binarios de largo fijo. Elegí como blockcipher al algoritmo Rijndael. Como no era el objetivo implementar un Rijndael desde cero, decidí utilizar la funcionalidad que brinda Crypto++ (cryptopp).

Para facilitar el asunto, voy a estar trabajando con bloques y claves de 128 bits (16 bytes).

Al cifrar un único bloque de largo fijo e igual a 128 bits, no necesito padding ni técnicas de block-chaining (ej. CBC). Por lo tanto, el modo en el que necesitaba usar AES es ECB sin padding. Recordemos que ECB no encadena bloques realmente y en caso de que el texto plano se repita, se repetirá también el cifrado leakeando información. Por favor nunca utilizar ECB para cifrar mensajes de más de un bloque.

Hechas estas consideraciones, este es el código:


Leer el resto del artículo »

3
Mar
2011

mtrace: debug de memoria en C (LibC)

La función mtrace proporcionada por LibC nos permite trazar todos las operaciones de obtención, redimensionamiento y liberación de memoria realizadas por las funciones malloc, realloc y free respectivamente. De esta forma, es posible detectar memory leaks (memoria sin liberar) en nuestra aplicación.

La función mtrace se vale de la variable de entorno MALLOC_TRACE para conocer la ruta donde guardar el resultado de las operaciones realizadas.

Con la función muntrace podemos detener el monitoreo iniciado por mtrace. Es posible encapsular bloques del programa con mtrace y muntrace.

Código de ejemplo:

#include <stdio .h>
#include <stdlib .h>
#include <mcheck .h>
 
int main () {
 
	setenv("MALLOC_TRACE", "/root/c/mtrace/output", 1);
 
	mtrace();
 
	void* puntero_a_memoria =  (void*)malloc(1);
 
	return 0;
}
</mcheck></stdlib></stdio>

Cambien el path /root/c/mtrace/out por el que les resulte conveniente. El proceso debe tener permisos de escritura allí.


Leer el resto del artículo »

3
Mar
2011

Variables de entorno con LibC

LibC provee algunas funciones para manejar las variables de entorno. Debemos incluir la Standard Library (stdlib.h) para acceder a ellas.

Limpiar las variables de entorno:

int clearenv(void);

Escribir o modificar una variable de entorno:

int putenv(char *string);

El parámetro string es de la forma VARIABLE=valor

Escribir o modificar una variable de entorno:

int setenv(const char *name, const char *value, int overwrite);

name es el nombre de la variable de entorno, value el valor y overwrite (0 o número distinto de 0) permite especificar la acción para el caso de que la variable de entorno ya exista con un valor determinado.

Remover una variable de entorno:

int unsetenv(const char *name);

name es el nombre de la variable de entorno.

2
Feb
2011

Debug de memoria en C con mcheck() y mprobe()

Comparto aquí un código con el que estuve haciendo algunas pruebas para debuguear memoria en C. Lo que hace es forzar errores escribiendo memoria no reservada y utilizar las funciones mcheck() y mprobe() de la librería GNU Libc para obtener información del error.

#include <stdio .h>
#include <stdlib .h>
#include <string .h>
#include <mcheck .h>
#include <malloc .h>
 
void error_memoria (enum mcheck_status estado_mcheck);
 
void error_memoria(enum mcheck_status estado_mcheck){
	printf("Llamada ocasional de mcheck() a error_memoria()\n");
}
 
main()
{
	//Chequeos de memoria ocasionales con mcheck
	int r = mcheck(error_memoria);
	if(r == 0)
		printf("Llamada a mcheck() ok\n");
	else if(r == -1)
		printf("Llamada a mcheck() tardía\n");
 
	//Reservar memoria y setearla en NULL para un array de chars de 6 lugares
	char* array_chars = (char*)malloc(sizeof(char)*6);
	memset(array_chars, '\0', 6);
 
	//Cargar esos lugares con el string "hola"
	strcpy(array_chars, "hola");
 
	//Iterar para obtener las direcciones de memoria y sus valores del array + 5 lugares fuera del array
	int i;
	for(i=0; i < sizeof(array_chars) + 5; i++){
		printf("Direccion %c: %x\n", array_chars[i], (int)&array_chars[i]);
 
		//Escribir fuera del array con valores NULL
		if(i >= sizeof(array_chars)){
			//Comentar esta línea para evitar este tipo de error
			array_chars[i] = '\0';
		}
	}
 
	//Obtener la direccion de memoria anterior al array y cargarle el valor NULL
	int mem0 = ((int)&array_chars[0]) - 1;
        char* ptr = (char*)mem0;
	//Descomentar esta línea para forzar la escritura anterior al bloque.
        //*ptr = '\0';
 
	//Descomentar esta línea para forzar un error del tipo 'memoria ya liberada'	
        //free(array_chars);
 
	//Realizar una comprobación de memoria con mprobe() al array de chars
	enum mcheck_status estado = mprobe(array_chars);
	switch (estado){
		case MCHECK_DISABLED:
			printf("Estado disabled: mcheck no fue llamado al principio. No se puede hacer una comprobación coherente de memoria.\n");
			break;
		case MCHECK_OK:
			printf("Estado ok: no hay inconsistencias detectadas\n");
			break;
		case MCHECK_HEAD:
			printf("Estado head: los datos inmediatamente anteriores al bloque reservado fueron modificados.\n");
			break;
		case MCHECK_TAIL:
			printf("Estado tail: los datos inmediatamente posteriores al bloque fueron modificados.\n");
			break;
		case MCHECK_FREE:
			printf("Estado free: el bloque ya fue liberado\n");
			break;
		default:
			break;
	}
}
</malloc></mcheck></string></stdlib></stdio>


Leer el resto del artículo »