RSS

Introdução a bibliotecas em C

Lendo post do meu amigo sigsegv sobre “ld preload”
fiquei motivado escrever algo sobre bibliotecas em C ,
algo bem informal bem como ajudar iniciantes.assim como fiz
no post de pkg-config.

master librarian

master librarian do game castlevania

Criando uma biblioteca estática (Static library)
———————————————————————
Quando a ligação é feita durante a criação de um executável ou
outro arquivo objeto, ele é conhecido como vinculação estática
ou early binding. Neste caso, a ligação é feita geralmente por
um linker, mas também pode ser feito pelo compilador. A biblioteca
estática, também conhecida como um archive, é que se destina a ser
ligada estaticamente.

vamos la

$ vim test.c

int sum(int a,int b)
{
 return a+b;
}

:wq!
para criar o arquivo com extensão “.o”
$ gcc -Wall -c test.c

passamos para “.a”
$ ar -cvq test.a test.o

pronto agora você pode usar sua bibliotéca estática
$ gcc -o a a.c test.a

também pode-se fazer
$ gcc -o a a.c -ltest

$ vim a.c

 #include <stdio.h>

 int main()
 {
  printf("%d \n",sum(2,2));
 }

:wq!

ao executar “a” devera resultar em “4” no stdout


Criando uma biblioteca dinâmica (Dynamic Library)

———————————————————-

Carregamento dinâmico é um mecanismo pelo qual um programa de computador pode, em
tempo de execução, carregar uma biblioteca (ou binário outros) para a memória,
recuperar os endereços de funções e variáveis contidas na biblioteca, executar
essas funções ou acessar essas variáveis, e descarregar o biblioteca da memória.

Ao contrário de vinculação estática e tempo de carregamento ligando, este mecanismo
permite que um programa de computador para a inicialização, na ausência destas
bibliotecas, para descobrir as bibliotecas disponíveis e potencialmente ganhar
funcionalidades adicionais.

No windows este tipo de biblioteca se chama DLL (dynamic-link library) em Unix Like
e afins chama-se DSOdynamic shared object

man ld.so” para mais informações

vamos la

$ gcc -Wall -fPIC -c test.c
$ gcc -shared -Wl,-soname,test.so.1 -o test.so.1.0 test.o
$ mv test.so.1.0 /lib
$ ln -sf /lib/test.so.1.0 /lib/test.so
$ ln -sf /lib/test.so.1.0 /lib/test.so.1

Entendendo os argv(argumentos)

-fPIC” seria uma diretiva para compilar de forma independente
Ideia é adicionar um nível adicional de indireção a todos os
dados globais e referências de função no código. utilizando algumas
partes da ligação e carregamento de processos, é possível fazer a
seção de texto da biblioteca compartilhada e independente
de posição, no sentido de que ele possa ser facilmente mapeado em diferentes
endereços da memória sem a necessidade de mudar um pouco.
-shared” Produzir um objeto compartilhado que pode ser relacionado com
outros objetos para formar um executável.
aqui explica melhor

um “man gcc” não faz mal para saúde 😉

na hora de compilar

$ gcc -Wall -I/path/to/include-files -L/path/to/libraries a.c -ltest -o a

ou também
$ gcc -Wall -L/lib a.c -ltest -o a

Por fim
————
bom aqui foi uma introdução bem superficial, sugiro estudar
autotools e cmake,bem como automatizar suas tarefas , não
conheço ninguém que goste deles, são muitas paradigmas a
seguir, muitos fins de semana a perder fazendo testes com
autoconf automake… Entretanto é um estudo que me parece
indispensável para quem quer ser um programador em C completo.

Para estudo do cmake(é bem mais fácil de usar) esse link
cmake

Caso queira estudar autotools(estou lendo este livro 😉 )
autotools

bom se este post não fui o suficiente para você sugiro que leia
o paper do meu amigo sigsegv sobre ELF para entender linkagem
das bibliotecas e algo mais… AQUI

Anúncios
 
Deixe um comentário

Publicado por em dezembro 17, 2011 em Linguagem C

 

the thief detector (detector de ladrão ) :-D

Post não vai ser sobre o carrinho de controle remoto com infravermelho
sim já terminei o protótipo dele já funciona, mas quero corroer a
placa fazer algo bem mais decente, invés de ficar usando breadboard.
como eu sou bem NOOB em tudo e em eletrônica este post vai demorar.

Olhe meu vídeo que você vai entender por que quero usar IR no carrinho

strikes back

Já algum tempo que comprei sensor de movimento para fazer um sistema
detector de “ladrão”, até pensei em usar um buzzer e tudo mais,
mas detector de ladrão com buzzer é muito manjado. Como eu gosto de trazer o que é
meio incomum para o blog então tive uma ideia…

Missão comunicação serial para quando for detectar o
movimento tirar uma foto da webcam e mandar e-mail com anexo a foto.
já tem soluções com o “motion” ou mesmo com opencv detectando movimentos
da webcam reconhecimento e tudo mais, mas a ideia do feito foi treinar
desenvolvimento com “arduino pro mini” em conjunto com “FTDI“…

material usado:
Arduino pro mini – $18.95 USD sparkfun (anda meio salgado o preço prefiro o diavolino )
Resistor 10k Ohm – $0.15 santa efigenia
Pir motion sensor – $9.95 USD sparkfun
Machine Pin headers – $2.00 santa efigenia (muito chato soldar isso no arduino)
FTDI Basic Breakout 5V – $12.00 USD sparkfun

vendo como fica
pronto1

seguindo a dica de
http://bildr.org/2011/06/pir_arduino/

código do arduino

int pirPin = 9; 

void setup(){
 Serial.begin(9600);
 pinMode(pirPin, INPUT);
}

void loop(){
  int pirVal = digitalRead(pirPin);


// achou movimento
  if(pirVal == LOW)
  { 
//pausa em milesegundos equivalente ao usleep do ansi C
     delay(500);
    Serial.println("1");
  }
  //sem movimento
  else
  {
    Serial.println("0");
  }

}

Lembra da nossa Missão ?
Se o arduino detectar valor com sensor de movimento
ira mandar um OUTPUT para a porta serial,nosso programa em C
irá ficar na esculta se ele julgar movimento do conjunto de
OUTPUT ele ira tirar uma SHOOT da WEBCAM e ira mandar e-mail
com anexo
a foto…

Vamos resolver o problema do E-mail,bom fazer um cliente de e-mail do zero
em C é trabalhoso e leva tempo, então vamos instalar cliente de e-mail
instalamos o “mutt

//use o gerenciador do seu OS,se for BSD use ports...
$ sudo apt-get install mutt
$ vi ~/.muttrc

set realname="seunome"
set from="exemplo@gmail.com;"
set my_user=exemplo@gmail.com
set my_pass='sua senha'
set smtp_url=smtps://$my_user:$my_pass@smtp.gmail.com
set ssl_force_tls = yes
:wq!

vamos testar

echo 'conteúdo do e-mail' | mutt -s 'assunto do e-mail' exemplo@gmail.com

e vá ver sua caixa de corrêio verificar…

como enviar nosso anexo ?

echo 'LogLog!!!' | mutt -s 'THief Get LOg' -a c/arduino/test.jpg -- exemplo@gmail.com

quer aprender mais sobre o mutt ? “man mutt

agora podemos partir para o código
não fique triste por eu ter usado o OpenCV para tirar foto da webcam

/*
contato: c00f3r@gmail.com
autor: Antonio Costa aka Cooler_
coolerlab.wordpress.com

Simples detector de ladrão usando Arduino+sensor de movimento

apt-get install libhighgui-dev  libcv
gcc -o thiefget thiefget.c  -lcv -lhighgui -lcxcore; ./thiefget

usei o OpenCV para tirar shoot da webcam pois não conheço outra API
que faça o mesmo...

só para enviar e-mail que usei programa de terceiro... parece gambi até xD

executando:
como argumento o seu dispositivo onde esta o arduino
./thiefget /dev/ttyUSB0


 */
#include <stdio.h>    
#include <stdlib.h> 
#include <string.h>   
#include <unistd.h>   
#include <termios.h>  
#include <fcntl.h> 
#include "opencv/cv.h"
#include "opencv/highgui.h"

// quantas vezes o sensor retornara 1 para mandar e-mail ?
#define MOVES 16

// numero que tolera erros
#define FAIL 16

// sempre concatene com 'B' a  taxa de transmissão ,"9600" padrão do AVR
#define BAUDRATE B9600

int serialboot(const char* serialport, int baud);
int serialread(int fd, char* buf, char until);
void webcam(const char* file);

void banner() 
{
 printf("\nFollow patern: ./PegaLadrao <SerialPort>\n"
  "Just Another geek Cool THing With ArduinO!!!\n"
  "Simple THief Get\n"
  "Coded By Cooler_\n"
  "coolerlab.wordpress.com\n"
  "\n");
}

int main(int argc, char *argv[]) 
{
 int baudrate = BAUDRATE,fd=0,counter=0,OFF=0; 
 char *buf=malloc(sizeof(char)*16);
 char *serialport=malloc(sizeof(char)*512);

  if(argc<2) 
  {
   banner();
   exit(EXIT_SUCCESS);
  }
    
  printf("Serial:%s\n",argv[1]);

//conection
  strncpy(serialport,argv[1],512);
  fd=serialboot(serialport, baudrate);

   if(fd<=0)
   {
    puts("veja se o dispositivo esta conectado!!");
    printf("%d\n",fd);
    exit(EXIT_SUCCESS);
   }
 
  while(1) 
  {
    
// tempo em milesegundos, altere como for necessário
   serialread(fd, buf, '\n');
   printf("====================\nread: %s\ncounter: %d\n===================\n",buf,counter);

// se ler "1" contador é atribuido
     if(strcmp(buf,"1")>0)
     {
      usleep(500000);
      puts("MOVEMENT ONLINE");
      puts(buf);
      counter++;
      OFF=0;
     } 
//numero de vezes que achou movimento
     if(counter==MOVES)
     {
      puts("cof cof thief in HOME");
      webcam("test.jpg");
      system("echo 'LogLog!!!' | mutt -s 'THief Get LOg' -a /home/nick/c/arduino/test.jpg -- exemplo@gmail.com");
      break;
      counter=0;
     } 
     if(!strlen(buf))
      OFF--;
     if(OFF==FAIL)
      break;
     
  }

 puts("Simple THief Get ,set to OFF");
 close(fd);
 free(buf);
 free(serialport);

 exit(EXIT_SUCCESS);    
} 

int serialread(int fd, char* buf, char until)
{
 char b[1];
 int i=0;
 do { 
  int n=read(fd, b, 1);  
  if(n==-1) 
    return -1;    
  if(!n) 
  {
   usleep(16000); 
   continue;
  }
  buf[i] = b[0]; 
  i++;
 } while(b[0]!=until);

 buf[i]=0;  

 return 0;
}

int serialboot(const char* serialport, int baud)
{
 struct termios toptions;
 int fd;

    fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);

    if(fd == -1)  
    {
     puts("serialboot: não foi possivel abrir a porta ");
     return -1;
    }
    
    if(tcgetattr(fd, &toptions) < 0) 
    {
     puts("serialboot: nao foi possivel pegar atributos do terminal");
     return -1;
    }
    speed_t brate = baud; 
    cfsetispeed(&toptions, brate);
    cfsetospeed(&toptions, brate);
   // para default recv com termios.h
    // 8N1
    toptions.c_cflag &= ~PARENB;
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag &= ~CSIZE;
    toptions.c_cflag |= CS8;
    // no flow control
    toptions.c_cflag &= ~CRTSCTS;
    toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
    toptions.c_oflag &= ~OPOST; // make raw

    // olhe http://unixwiz.net/techtips/termios-vmin-vtime.html
    toptions.c_cc[VMIN]  = 0;
    toptions.c_cc[VTIME] = 20;
    
    if(tcsetattr(fd, TCSANOW, &toptions) < 0) 
    {
     puts("serialboot: nao foi possivel adicionar atributos no term erro 1");
     return -1;
    }

 return fd;
}

/*tira foto usando opencv
  não queria usar opencv, mas unica API que ja tinha
 usado com a webcam...
*/
void webcam(const char* file)
{
 CvCapture *capture = cvCreateCameraCapture(0);
   if(capture==NULL)
    puts( "nao he possivel pegar foto!\n");

  IplImage* frame = cvQueryFrame( capture );
   if(!frame)
    puts( "erro na foto!\n");

  int imageParams[3] = {CV_IMWRITE_JPEG_QUALITY, 100, 0};
  cvSaveImage(file , frame,imageParams);
  cvReleaseCapture( &capture );
}

veja o e-mail que chegou quando cheguei proximo do sensor
e-mailcooler

muito divertido…

bom é isso ai,
escrevi o código meio que na correria mas acho
que deu para explanar a ideia…
fique avontade para melhorar o código 😉

 
8 Comentários

Publicado por em dezembro 4, 2011 em arduino, hacking, Linguagem C, segurança de sistemas

 

A magia dos Bits

Antes de entender a magia dos bits vamos ver algo leve, claro em
linguagem C , bem como dar uma introdução ao entendimento de bits
e seu funcionamento em variáveis.

Captura de Tela 2014-07-14 às 21.14.21

Uma variável do tipo “int” tem 4bytes ou seja 32bits

se você faz:

 "int var = 3;"

Então temos:

4bytes = 32bits
cada octeto é um byte, meio octeto pode-se chamar de nibble.
“…00000000 00000000 00000011”

cada casa de número binário contamos como um bit
bit nada mais é que mnemônico para “Binary digiT”

Para saber número de bytes de uma variável usamos operador “sizeof(var)”
que nos retorna o valor em bytes da variável.

Se desejamos saber valor binário de um número fazemos divisão por 2
e enquanto o resto da divisão for diferente de “1” fazemos a divisão
no final pegamos os restos ao contrário para ser o resultado final

número 12 para binário logo:

12 | 2
12 +------                   1100 <-- resultado ao contrário
 0  6    | 2              -------------
         +-----
    0      3  | 2
              +-----
          1     1

Resultado 1100,repare que só temos um nibble ou seja um semiocteto
metade de 1 byte ou seja 4bits, lembra 1byte é 8 bits.

façamos então um programa para automatizar a tarefa de converter
decimal para binário

#include <stdio.h>

int main()
{
 int bin[8],num=0,counter=0;

 puts("Dec2Bin\n digite um numero");
 scanf("%d",&num);

//para somente quando a divisão der "1"
 while(num!=1)
 {
//pegamos o resto da divisão ou se tiver um resultado é 1 se não é 0
  bin[counter]=(num%2)?1:0;
//dividimos num por 2 e armazenamos em num para pegar o próximo resto
  num/=2;
  counter++;
 }
 bin[counter]=num;

//mostramos o array ao contrário
 printf("\nResultado: ");
 while(counter!=-1)
 {
  printf("%d",bin[counter]);
  counter--;
 }
 printf("\n");

 return 0;
}

continuando, tem outra forma melhor de se fazer isso, mas não
é hora de abordar isso agora.

Introdução Escovação de Bits “BitWise”
=======================================

Quando dizemos escovação de bits é uma mera referência ao trabalho
de manipular bits para se obter certos resultados. pessoal que trabalha
com microcontrolador seja AVR,PIC por muitas vezes tem que fazer tal
manipulação. Quando queremos desempenho escovação de bits pode nos
ajudar também embora o compilador já otimize muitas das tarefas.Outra
utilização é em tratamento de imagens e manipulação das mesmas,OpenCV
mesmo obriga você usar sempre que não existe uma solução pronta…

Bit Shifting “deslocamento de bit”
======================================

Deslocar um bit nada mais é que mudar o bit da sua posição original
para se chegar num certo resultado,chamamos esta técnica de bit shift
é um mnemônico do assembly “shl,shr”(shifiting left,shifiting right),
vamos a um exemplo de deslocamento para esquerda:

 int var = 3;
 var <<= 1;

 o nosso 3

  0011

 recebeu um deslocamento para esquerda

  0110

resultou em “6”, pode dar uma ilusão de aritmética de produto ou de
adição por ele mesmo, mas foi o resultado do deslocamento, forma
matemática correta segundo o livro do K&R para explanar nossa expressão
do exemplo seria “2*3¹”.

agora vamos ver deslocamento para direita:

 int var = 100;

 temos então 1100100

 var >>= 2; 

 removemos os dois últimos digitos 

  11001

nos resulta “25”,forma matemática para tal é a seguinte “(100/2)²”
você me diz 25mil, cadê os zeros ? como disse remove os dois últimos
dígitos.

Mascaramento de Bit
======================

OR

Vamos ao operador “|” tem o mnemonico “OR” em assembly, vamos entender seu impacto

 x=26|19;

   11010
 | 10011
 ---------
   11011   ==  27

AND

Agora o “&” mnemônico com “AND” em assembly

 x=26&19;

   11010
 & 10011
 ---------
   10010 == 18

NOT

O “~” é mnemônico com “NOT” ou seja ele é uma negação, fazendo um efeito inverso
do seu valor carregado, ou seja onde está 1 fica zero e vice e versa.

 x=~26; 

  11010
   flip
  00101

resultado seria -27, Como mas por que não 5 ? lembra que falei um “int” é
4 bytes equivale a 32bits, então

0000 0000 0001 1010

1111 1111 1110 0101

agora sim,eu fiz em nibble para não precisar escrever muito…

XOR

O “^” é mnemônico para o XOR

 x=26^19;

   11010
 ^ 10011
 ---------
   01001  == 9

veja se a tabela ne ajuda

,---,---,--------,
| a | b |  a ^ b |  pode-se fazer SWAP sem usar uma terceira variável
|---|---|--------|  exemplo:
| 0 | 0 |   0    |
| 0 | 1 |   1    |  int A=4,B=7;
| 1 | 0 |   1    |  A^=B; B^=A; A^=B;
| 1 | 1 |   0    |  // "A" agora vale 7
'---'---'--------'
 alguns usam XOR em criptografia também...

Escovando Bits
================

Vamos usar bitwise para obter “desempenho” vejamos
alguns códigos com bitwise


// programa para verificar se é impar ou par
main(int argc,char *argv[]){printf("%s\x0a",(!((atoi(argv[1]))&1))?"Par":"impar");}
// Isso = "x&1" usa mesma lógica disso "x%2"
// se retornar 0 é por que o último num binário é ZERO ou seja PAR...

// Sempre que precisar verificar se um número é multiplo
// fazer
resto = num & (divisor - 1);
x = 122 % 6;
//forma mais rápida
x = 122 & (6 - 1);

/*
se quiser fazer casting de float para Int
invés de fazer Casting de Float para Int assim "x = int(3.142)",
faça assim "x=3.142>>0;", melhora desempenho em 10%
*/
//operações ternárias são rapidas mas bit a bit são mais</b>
//invés
i = x < 0 ? -x : x;
//faça
i = (x ^ (x >> 31)) - (x >> 31);

//Comparando dois inteiros
x = a * b > 0;
//melhor forma
x = a ^ b >= 0;

//Comparar duas variáveis ver qual é a maior e menor
gamma = y ^ ((x ^ y) & -(x < y)); // gamma=menor(x, y)
gamma = x ^ ((x ^ y) & -(x < y)); // gamma=maior(x, y)

//Determinar se um inteiro é uma potência de 2
x = v && !(v & (v - 1));
//vai retornar verdadeiro ou falso 😉

//média para int
int a=6,b=8; printf("%d\n",((a&b)+(a^b)>>1));

//verificar se a posição "n" em bit é "1"
if( n & 1 << i ) 

lembra do nosso código simples de converter decimal para binário
vamos fazer um usando escovação de bits 🙂

// retirado da header beer.h https://github.com/CoolerVoid/C/edit/master/beer.h
char * dec2bin(int n, char * string)
{
 int i;
 static int size = 8 * sizeof(int);

  for(i = size - 1; i >= 0; i--, n >>= 1)
   string[i] = (01 & n) + '0';

 string[size] = '\0';
 return string;
}

calcular raiz quadrada escovando bit por que não…

// retirado da header beer.h https://github.com/CoolerVoid/C/edit/master/beer.h
int bit_sqrt(int num)
{
//so 32 is sizeof(int)<<3
 int num0=num,result=0,tbit=1<<((sizeof(int)<<3)-2);

 if(num<=0)
 {
  printf("error bit_sqrt(), num = %d ",num);
  return -1;
 }

 while(tbit>num0)
  tbit>>=2;
 while(tbit^0)
 {
  if(num0>=result+tbit)
  {
   num0-=result+tbit;
   result=(result>>1)+tbit;
  }else
   result>>=1;
  tbit>>=2;
 }
 return result;
}

não se compara esta função a de APIs como GMP,OpenSSL
mesmo por que é uma função simples muito menos a “math.h”,
foi mais para ilustrar.

posso usar bitwise em strings ?
se for um ponteiro por que não

// return reverse string
char *strrev(char *str)
{
 char *p1, *p2;

 if(! str || ! *str)
  return str;
 for(p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
 {
  *p1 ^= *p2;
  *p2 ^= *p1;
  *p1 ^= *p2;
 }
 return str;
}

esse assunto é gigante vou ficar por aqui, por final
sugiro que leiam caso queiram se aprofundar no assunto
de bitwise , o livro “hacker’s delight”

hackers delight

2d175-hackers_delight

 
9 Comentários

Publicado por em novembro 24, 2011 em hacking, Linguagem C, math

 

Race Conditions

O que é ?

Em palavras simples “Race Condition” é rotulado quando o código é uma condição não atômica ou seja thread-unsafe e não reentrante, uma condição de corrida é um comportamento anômalo causado pela dependência inesperada no tempo relativo de eventos, Race Condition pode ter vários contextos tais como em “threads”, “Time of check, time of use race condition”,”switch” em adição quando o desenvolvedor não trata todos os dados de entrada “stdin”, algum desses dados pode comprometer a integridade do sistema seja abrindo algum arquivo como “/etc/shadow“, fazendo disclosure de outros arquivos que você não gostaria, sim pode ter relação direta com a falha LFD(Local File Disclosure) na maioria dos casos comuns, mas condições de corrida estão além, imagina você manipular um arquivo temporário e criar um link simbólico para o local do qual gostaria, vou tentar passar um conceito básico neste post.
road_rash_-_1992_-_electronic_arts1
Vamos a um exemplo, tudo começa com uma má prática de permissão
ou acesso no file system com uso sem tratamento dos dados dos argumentos
passados para os syscalls exemplo open(),read(),chmod(),symlink(),unlink(),
lchown(),chown()
entre outras funções que envolve manipulação de permissões e
arquivos , “háha mais eu uso fopen()” rode um “strace” no executável do
seu programa que você terá uma surpresa o syscall open() estará la.
linguagens como Java,Perl,Ruby dependem da libC para rodar em unix
like fora as syscalls então não são imunes ao problema , irei mostrar
um ponto empírico;

cooler@lisperian:/etc$ LD_TRACE_LOADED_OBJECTS=1 jvm
linux-gate.so.1 => (0x0022a000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0x0093f000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0x00e12000)
libutil.so.1 => /lib/i386-linux-gnu/libutil.so.1 (0x00183000)
libssl.so.1.0.0 => /lib/i386-linux-gnu/libssl.so.1.0.0 (0x0018a000)
libcrypto.so.1.0.0 => /lib/i386-linux-gnu/libcrypto.so.1.0.0 (0x0031a000)
libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0x00110000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0x00c15000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00641000) --> aqui libC
/lib/ld-linux.so.2 (0x00b20000)

Relaxe normal a “jvm” do java depender de C ,poh DMR morreu ninguém falo nada
se fosse o James Gosling! hehehe…

Ao falar de “Race Conditions” no contexto de “threads”, temos duas formas condições não atômicas
e atômicas ,condições atômicas não são vulneráveis , mas as condições não atômicas
são vulneráveis são thread-unsafe e não reentrantes.

*O que é “não reentrante” ?

Não reentrante refere-se a qualidade duma subrotina de ser executada concorrentemente
de forma insegura, é exatamente o antônimo de reentrante que seria uma subrotina segura.

Ex:


 int madruga = 2;

 int foo()
 {
   madruga += 8;
   return madruga;
 }

 int gamma()
 {
   return ( ( foo() -4 ) << 2) ;
 }

Se duas thread executar uma função seja foo() ou gamma()
vai dar algum bug com atropelamento da variável madruga
dando um resultado inesperado…

* O que é Thread-unsafe ?

A thread fica insegura quando os dados de forma concorrentemente
são alterados por usar uma variável global ou por não usar Lock por
mutex , quando usamos fork() não precisamos nos preocupar, mas ao usar
pthread por exemplo deve-se ter controle seja com mutex ou com semáfaros.

Ex

// gcc -o code code.c -lpthread
#include <stdio.h>
#include <malloc.h>
#include <pthread.h>

int y=1;

void *foo(void * sum)
{
 y+=*(int *)sum;
 printf(" result: %d \n",y);
}

int main()
{
 int x=0,num_thread=20;
 void *pointer=&y;

 pthread_t * threads;
 threads = (pthread_t *) malloc(num_thread * sizeof (pthread_t));

  for(x = 0; x < num_thread; x++)
   if(pthread_create (&threads[x], NULL, foo, pointer) != 0)
    error ("pthread_create");

  for(x = 0; x < num_thread; x++)
   pthread_join (threads[x], NULL);

 free(threads);
 return 0;
}

veja que este código é executado sem nenhum controle dos dados
ficam de acordo com o acaso de uma entropia da concorrência das
threads…

vamos passar o valgrind usando a tool helgrind para analisar o programa

cooler@lisperian:~/race_condition$ valgrind --tool=helgrind ./thread
==4543== Helgrind, a thread error detector
==4543== Copyright (C) 2007-2010, and GNU GPL'd, by OpenWorks LLP et al.
==4543== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==4543== Command: ./thread
==4543==
resultado 2
==4543== Thread #3 was created
==4543== at 0x413A0B8: clone (clone.S:111)
==4543==
==4543== Thread #2 was created
==4543== at 0x413A0B8: clone (clone.S:111)
==4543==
==4543== Possible data race during read of size 4 at 0x804a028 by thread #3
==4543== at 0x804855D: foo (in /home/cooler/info_leak/race_condition/thread)
==4543== by 0x4028F62: mythread_wrapper (hg_intercepts.c:221)
==4543== by 0x4052D30: start_thread (pthread_create.c:304)
==4543== by 0x413A0CD: clone (clone.S:130)
==4543== This conflicts with a previous write of size 4 by thread #2
==4543== at 0x8048566: foo (in /home/cooler/info_leak/race_condition/thread)
==4543== by 0x4028F62: mythread_wrapper (hg_intercepts.c:221)
==4543== by 0x4052D30: start_thread (pthread_create.c:304)
==4543== by 0x413A0CD: clone (clone.S:130)
==4543==
==4543== Possible data race during write of size 4 at 0x804a028 by thread #3
==4543== at 0x8048566: foo (in /home/cooler/info_leak/race_condition/thread)
==4543== by 0x4028F62: mythread_wrapper (hg_intercepts.c:221)
==4543== by 0x4052D30: start_thread (pthread_create.c:304)
==4543== by 0x413A0CD: clone (clone.S:130)
==4543== This conflicts with a previous write of size 4 by thread #2
==4543== at 0x8048566: foo (in /home/cooler/info_leak/race_condition/thread)
==4543== by 0x4028F62: mythread_wrapper (hg_intercepts.c:221)
==4543== by 0x4052D30: start_thread (pthread_create.c:304)
==4543== by 0x413A0CD: clone (clone.S:130)
==4543==
resultado 4
resultado 8
resultado 16
resultado 32
resultado 64
resultado 128
resultado 256
resultado 512
resultado 1024
resultado 2048
resultado 4096
resultado 8192
resultado 16384
resultado 32768
resultado 65536
resultado 131072
resultado 262144
resultado 524288
resultado 1048576
==4543==
==4543== For counts of detected and suppressed errors, rerun with: -v
==4543== Use --history-level=approx or =none to gain increased speed, at
==4543== the cost of reduced accuracy of conflicting-access information
==4543== ERROR SUMMARY: 38 errors from 2 contexts (suppressed: 715 from 32)

O próprio valgrind já disse tudo …

Quanto ao fopen(),open() fica uma dica de como fazer da forma segura:

https://www.securecoding.cert.org/confluence/display/seccode/FIO03-C.+Do+not+make+assumptions+about+fopen%28%29+and+file+creation

Lembrando sempre de validar close(),fclose() também…

https://www.securecoding.cert.org/confluence/display/seccode/FIO22-C.+Close+files+before+spawning+processes

 

* Veja alguns exploits

-Famoso XPL que se aproveita de um race condition “h00lyshit”

-Race condition no bzexe pode comprometer integridade de um sistema veja

e muitos outros…

Nos casos mais comuns é se aproveitar de um arquivo aberto para usar “symlink()”
para dar disclosure de um “/etc/shadow” por exemplo, muitos programadores cometem erros
em permissões ou em usar “open()”, a dica em arquivos é usar “flock()” .

Um obrigado ao meu brother “sigsegv“,que está presente no servidor irc.freenode.net
canal #c-br, Valeu pela dicas de race condition sigsegv 😉

 
1 comentário

Publicado por em novembro 10, 2011 em hacking, Linguagem C, segurança de sistemas

 

Micro estação meteorológica com arduino

Bom ideia partiu de um colega que trabalhou com meteorologia , ele precisava de um sistema
que armazena-se temperatura do tempo durante cada dia e depois de 30 dias ou mais ele
precisava saber o temperatura de cada dia, ele me mostrou o sistema que tinha feito com arduino,
bom pensei por que não fazer igual ? bom de primeira ele me aconselhou usar sensor digital
invés de analógico , usar baterias de lítio etc…

bom não terminei a micro estação meteorológica mas já andei fazendo alguns protótipos
vou ilustrar o que foi feito,olhamos o material

1X – protoboard
1X – 4.7K ohm Resistor
2X – DS18B20 (nosso sensor de temperatura)

vendo como fica na protoboard
sensortemp

Até aqui você deve de gastar uns 20 reais , mais para ficar mais legal vou usar
um display de LCD,não ter que passar os dados via porta serial…

veja meu video

o código

// coded by Cooler_

// vide http://www.arduino.cc/en/Tutorial/LiquidCrystal
#include <LiquidCrystal.h>
/* biblioteca de dallas
   cp -rf OneWire /usr/share/arduino/libraries 
   http://www.arduino.cc/playground/Learning/OneWire   
*/
#include <OneWire.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

OneWire  ds(7);  // pin of sensor
void setup(void) {
  lcd.begin(16, 2);
  lcd.print("Coded by Cooler_");
  delay(3050);
  lcd.begin(16, 2);
  lcd.print("irc.freenode.net ");
  lcd.setCursor(0, 1);
  lcd.print("#c-br #reset");
  delay(3050);
  lcd.begin(16, 2);
  lcd.print("Cogumelo Binario");
}

void loop(void) {
  byte i=0,x=0;
  byte type_s;
  byte valores[12],addr[8];
  float celsius;
  
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // inicia a conversão
  delay(1000);     // talvez 750ms  ou ñ

  x = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  while(i < 9) {           // precisamos de 9 bytes
    valores[i] = ds.read();
    i++;
  }

  // coverte var valores para temperatura atual
//escovação de bit padrão para o funcionamento
  unsigned int raw= ( valores[1] << 8 ) | valores [0];
  if(type_s) {
    raw = raw << 3; // 9 bit para esquerda
    if (valores[7] == 0x10) {
      // contador com 12bit
      raw = (raw & 0xFFF0) + 12 - valores[6];
    }
  } else {
    byte cfg=(valores[4] & 0x60);
    if(cfg == 0x00) raw = raw << 3;  // 9 bit res, 93.85 ms
    else if(cfg == 0x20) raw = raw << 2; // 10 bit res, 187.15 ms
    else if(cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
    // padrão é 12 bit , 750 ms tempo da resolução 
  }
  celsius = (float)raw / 16.0;
//bota o cursor na linha de baixo para mostrar a temperatura
  lcd.setCursor(0, 1);
  lcd.print("temperatura:"); delay(30);
  lcd.print(celsius); lcd.print("-");
  lcd.print("Cogumelo Binario"); lcd.print("-");
}

Código bem simples para algo simples,ideia agora é usar um cartão SD
para gravar os dados e claro quando for guardar na caixa hermética tirar
o display de LCD não tem lógica usar o mesmo já que não queremos mostrar a
temperatura.

vou deixar link que estou estudando para conseguir trabalhar com cartão SD
http://code.google.com/p/sdfatlib/

 
1 comentário

Publicado por em novembro 8, 2011 em arduino, Linguagem C

 

Saindo dos pesadelos com ponteiros

Geralmente meio acadêmico da uma explicação de ponteiros deixando todos enrolados com apenas o básico , o que faz todos desviar do caminho dos ponteiros , os poucos que usam são aqueles que tem sido autodidata, bom alguns livros tem exemplos bons de ponteiros como no livro Ansi C do K&R, entretanto a falta de popularidade de tais dicas torna tal assunto meio obscuro…

*Perguntas frenéticas
Por que usar ponteiros ?
–Desempenho e maior manipulação dos dados,  fácil para depurar problemas…
E se eu não usar ?
–Na depuração de códigos STACK é bem complicada comparada com HEAP(uso do malloc(),sbrk()..), no tratamento de dados gigantes poderá ter algumas Traps Malditas!… (sim com alloca() pode usar ponteiro entretanto usaria STACK)
neca-elm-street-1-600x420

O que é ponteiro ?
Nada mais é que uma refêrencia , um tipo de dado que aponta dados que estão armazenados na memória, ponteiros são uma abstração da capacidade de endereçamento fornecidas pelas arquiteturas modernas. Em termos simples, um endereço de memória, ou índice numérico, é definido para cada unidade de memória no sistema, no qual a unidade é tipicamente um byte ou uma word, o que em termos práticos transforma toda a memória em um grande vetor.1 Logo, a partir de um endereço, é possível obter do sistema o valor armazenado na unidade de memória de tal endereço. O ponteiro é um tipo de dado que armazena um endereço…

Vamos a um exemplo básico para depois ver algo complexo

#include <stdio.h>
#include <string.h>

int main()
{
// ponteiro com int
 int *x,*y; // antes de usar um ponteiro é bom inicializar com "NULL", mas como é apenas exemplo de começo fica sem ;-[

// fazemos o casting para ponteiro de int
 x=(int *)256;
 y=(int *)256;
// casting para int antes da adição
 printf("%d \n",((int)x)+((int)y));

 puts("digite um numero para adicao com y...");
 scanf("%d",&x);
 printf("%d \n",((int)x)+((int)y));

// ponteiro com strings...
 char *word;

 word="ola";
 puts(word);
 word="lol";
 puts(word);
// 0[l] 1[o] 2[l]   word[2] logo temos "l"
 printf("char: %c \n",*(word+2));

 return 0;
}

vamos entender algumas práticas comuns de se ver depois e partir para exemplos

 int i           //Int variável 'i'
 int *p          //'P' ponteiro para um int
 int a[]         //Matriz 'a' de Int
 int f()         //'F' função com valor de retorno do tipo int
 int **p         //'Pp' ponteiro para um ponteiro para um int
 int (*pa)[]     //'Pa' ponteiro para um array de int
 int (*pf)()     //pf ponteiro para uma função com valor de retorno int
 int *p[]       //Array 'p' de ponteiros para um int
 int *var()       //Função "var", que retorna um ponteiro para um int
 int ***var       //'var' ponteiro para um ponteiro para um ponteiro para um int
 int (**var)[]  //'var' ponteiro para um ponteiro para um array de int
 int (**var)()  //'var' ponteiro para um ponteiro para uma função com valor de retorno do tipo int
 int *(*c)[]  //'c' ponteiro para uma matriz de ponteiros para um int
 int *(*c)()  //"c 'ponteiro para uma função com valor de retorno do tipo ponteiro para um int
 int **app[]    //'App' ponteiro para um ponteiro para uma matriz de ponteiros para um int
 int (*b[])[] //Uma série de 'b' ponteiros para um array de int
 int (*c[])() /Um array 'c' ponteiros para uma função com valor de retorno do tipo int
 int ***fpp()   //"Fpp 'função que retorna um ponteiro para um ponteiro para um ponteiro para um int
 int (*fpa())[] //Função 'fpa ", que retorna um ponteiro para um array de int
 int (*fpf())() //"FPF" função que retorna um ponteiro para uma função com valor de retorno int

Fique calmo não é para decorar , tenha em mente leitura da esquerda para direita, e sempre começando pelo nome da variável…

Uma prática muito comum em C é usar void pointer, para muitos que estão iniciando não é normal, entretanto estudando códigos de terceiros pode-se ver muito , usar ponteiro colabora no desempenho e o código em
Assembly gerado fica menor de fato,um “disassemble main” no GDB pode te dar ponto empírico.

Um exemplo vale mais do que mil palavras:

// exemplo void pointer by Cooler_
#include <stdio.h>

//ideia de polimorfismo
void foo(void *point,int size)
{
// int == 4 bytes
 if(size==sizeof(int))
//tem que fazer casting do ponteiro para STDOUT
  printf("int : %d , bytes: %d\n",*(int *)point,sizeof(point));

// double == 8 bytes
 if(size==sizeof(double))
//casting de novo para o write(1...
  printf("double : %f , bytes: %d\n",*(double *)point,sizeof(double));
}

int main()
{
 int a=64;
 double b=3.14;

 printf("bytes do void : %d\n",sizeof(void));
// & usamos para dizer o endereço da memória de determinada variável
 foo(&a,sizeof(int));
 foo(&b,sizeof(double));

 return 0;
}

Outro exemplo seguindo a mesma lógica

#include <stdio.h>
#include <string.h>

typedef struct _myst
{
 int a;
 char b[10];
}myst;

void func(myst *mt)
{
 printf("resposta %d %s \n",mt->a,mt->b);
}

int main()
{
 void (*resposta)(void *);

 myst x;
 x.a=4;
 strncpy(x.b,"1234",9);
 resposta = (void*)func;
 resposta(&x);

 return 0;
}

Outra prática muito vista é o “ponteiro de arrays para funções“,
vejamos terceiro exemplo:

// example pointer of arrays to function by Cooler_
#include <stdio.h>
#include <malloc.h>

void foo1(int x)
{
 printf("int: %d\n",x);
}

void foo2(int x)
{
 printf("num: %d\n",x);
}

void foo3(int z)
{
 printf("result %d\n",z*z);
}

void func2func(void (*fp)(void *), void *q)
{
  fp(q);
}

int main()
{
//se a função tiver mais de um argv use "," (int,char...
 void (**list)(int);
//alocamos 3 endereços na heap
 list=(void *)malloc(3*sizeof(void *));

 list[0]=foo1;
 list[0](2);
 list[1]=foo2;
 list[1](4);
 list[2]=foo3;
 list[2](8);

 // função para função lol
 func2func(foo2, 4);

 free(list);
 return 0;
}

Outro exemplo usando função com argumento para função:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define w printf
#define MAX_BUF 128
#define array_num(array) (sizeof(array) / sizeof *(array))

void bubble(void *p, int width, int N,int(*fptr)(const void *, const void *));
int compara_letras(const void *m, const void *n);
int compara_numeros(const void *m, const void *n);

int main()
{
 int lista[]={4,2,1,5,3,8,10,9,0,45};
 char nomes[6][20] = {"Madruga","Arara","Zebra","Elefante","Babaca","Gato"};
 short i;

 for(i=0; i<=array_num(lista)-1; i++)
  w("%d\n",lista[i]);
 for(i=0; i<=array_num(nomes)-1; i++)
  w("%s\n",nomes[i]);
 w("--------------\nagora dando buble sort nas listas\n");
 bubble(lista, 4, 10, compara_numeros);
 bubble(nomes, 20, 6, compara_letras);
 for(i=0; i<=9; i++)
  w("%d\n",lista[i]);
 for(i=0; i<=5; i++)
  w("%s\n",nomes[i]);

 return 0;
}

// função com argumento para função
void bubble(void *p, int width, int N, int(*fptr)(const void *, const void *))
{
 int i, j, k;
 unsigned char buf[MAX_BUF];
 unsigned char *bp = p;
  for(i = N-1; i >= 0; i--)
  {
   for(j = 1; j <= i; j++)
   {
//repare que fptr é a função escolhida pelo usuário
    k = fptr((void *)(bp + width*(j-1)), (void *)(bp + j*width));
    if(k > 0)
    {
     memcpy(buf, bp + width*(j-1), width);
     memcpy(bp + width*(j-1), bp + j*width , width);
     memcpy(bp + j*width, buf, width);
    }
   }
  }
}
//comparando letras graças "strcmp" função da lib "string.h"
  int compara_letras(const void *m, const void *n)
  {
   char *m1 = (char *)m;
   char *n1 = (char *)n;
   return (strcmp(m1,n1));
  }
//comparando numeros
  int compara_numeros(const void *m, const void *n)
  {
   long *m1, *n1;
   m1 = (long *)m;
   n1 = (long *)n;
   return (*m1 > *n1);
  }

Outro exemplo arrays tridimensionais com ponteiros

/*
 *   Explanação arrays tridimensionais com Ponteiros
 *
 *
 *
 * c00f3r[at]gmail[dot]com
 * by Cooler_
 */
#include <stdio.h>
#include <stdlib.h>

int main()
{
/* array tridimensional
 *
 * [][][]
 * | | |_posição do caracter, todos caracter formam 1 palavra
 * | |___número da posição onde esta a palavra
 * |____ número da lista de palavras a usar
 *

 */
//  produto por 2 de char** pois vamos fazer 2 listas de palavras
 char ***lists=(char ***)malloc( 2*sizeof(char **)   );

//produto por 3 em char* pq vamos usar 3 palavras
 *(lists+0)=(char **)malloc(3*sizeof(char *));
// pode-se fazer tb lists[0][0]="ola"
 *(*(lists+0)+0)="ola";
 *(*(lists+0)+1)="Yay";
 *(*(lists+0)+2)="lol";
// adiciona mais um elemento caso queira
 lists[0][3]=(char *)realloc(lists[0],4*sizeof(char *));
 *(*(lists+0)+3)="iai";

 *(lists+1)=(char **)malloc(3*sizeof(char *));
 *(*(lists+1)+0)="epic";
 *(*(lists+1)+1)="let";
 *(*(lists+1)+2)="omg";

 fprintf(stdout," %s \n %s \n %c\n",lists[0][2],lists[1][0],lists[0][0][1]);
/* mostrando uma saida qualquer
 repare o terceiro elemento palavra "ola" segunda letra "l"

lists[0][0][1]='l'
            |
 [o][l][a] _|
  0  1  2
*/

// usar free() onde usou malloc() para liberar memória HEAP
 free(lists[0]);
 free(lists[1]);
 free(lists);

// caso use windows coloque um pause aqui no final 😉
 return 0;
}

Exemplo ,uma agenda simples usando struct com ponteiros

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// by Cooler agenda exemplo

//limite cadastros
#define LIMITE 1024 

#define BUFFER 32

//macro Anti Bug do "new line" comum em compiladores antigos, 1 para ativar 0 para desativar
#define ANTBUG 1

struct agenda  {
 char nome[BUFFER];
 int ra;
};

struct agenda list[LIMITE],carry;
struct agenda *lista=list;

int cmp(const void *a, const void *b)
{
//faz o casting para struct e verifica em ordem decrescente
 struct agenda *ia = (struct agenda *)a;
 struct agenda *ib = (struct agenda *)b;
 return (strcmp(ia->nome,ib->nome));
}

void banner()
{
 puts("\ncode agenda by cooler\n digite numero da opção\n 0- exit\n 1 inserir\n 2 remover \n 3 listar \n 4 listar em ordem de nome\n");
}

void inserir (int count)
{
 if(count != LIMITE)
 {
  puts("\ndigite nome");
  scanf("%30s",lista[count].nome);
#if ANTBUG
  getchar();
#endif
  puts("\ndigite RA");
  scanf("%6d",&lista[count].ra);
#if ANTBUG
  getchar();
#endif
 }
 else {
  puts("agenda cheia");
 }
}

void delete(int count)
{
 int position=0,count3=0,count2=0;

 puts("qual RA para remover cadastro ?\n");
 scanf("%6d",&position);
#if ANTBUG
  getchar();
#endif

 count3=count;

 while(count)
 {
   if(lista[count].ra == position)
   {
    count2=count;

    while(count2<count3)
    {
     carry=lista[count2];
     lista[count2]=lista[count2+1];
     lista[count2+1]=carry;
     count2++;
    }

    break;
   }
  count--;
 }

}

void listar(int count)
{
 while(count)
 {
  fprintf(stdout,"Nome: %s  RA: %d   position: %d\n",lista[count].nome,lista[count].ra,count);
  count--;
 }
}

int main()
{
 int escolha=1,count=0;

 while(escolha)
 {
  banner();
  scanf("%1d",&escolha);
#if ANTBUG
  getchar();
#endif
  switch(escolha)
  {
   case 1:
    count++;
    inserir(count);
   break;

   case 2:
    delete(count);
    count--;
    break;

   case 3:
    listar(count);
   break;

   case 4:
// quicksort para organizar por nome nossa lista
    qsort(lista,count+1,sizeof(struct agenda),cmp);
    listar(count);
   break;
  }
 }

 puts("saindo");

 return 0;
}

tem muitas dicas sobre o mesmo por ai, mas vou dar uma sugestão de leitura caso queira melhorar ainda mais em ponteiros famoso livro da truta 🙂
expert C

e também esse material de stanford,  espero ter ajudado 😉

 
5 Comentários

Publicado por em outubro 30, 2011 em Linguagem C

 

pkg-config informações sobre as bibliotecas

Bom dia Boa noite galera,tempinho ai que não mando algo paro blog,
mais aqui está um assunto interessante que muitos iniciantes ficam
perdidos em linguagem C, nada muito difícil algo bem sútil para
aprendizado.

Para instalar uma “API” para desenvolvimento em sistemas unix
á várias formas em Ruby por exemplo se usa gems,em Perl temos
o CPAN, Common Lisp temos asdf. E em C ? isso varia de distro
para distro pode-se usar apt-get,yum,pacman e os *BSD o ports
de acordo com o Sistema Operacional, entretanto todos tem o nome
do pacote semelhante na maioria das vezes podendo ter alguma
otimização ou versão mais atual dependendo se é current ,stable
em fim, por exemplo de pkg(pacote) vamos sitar uma API bem popular
a biblioteca do Curl ou seja libCurl, para poder usar temos que
instalar, podemos baixar o tarball extrair dar config,make,make install
ou podemos buscar nos repositórios exemplo se procurarmos “libcurl
não vamos encontrar um nome exato , você vai ver muitos tipos de
pacotes exemplo “libcurl-dev” que o “dev” significa development é
um pkg para desenvolvedor.

Outro argumento no final do pacote é o “doc” que significa
que é para documentação você vai poder usar o “man libcurl” por
exemplo,”dbg” pkg vem compilado com símbolos para depuração.

Algo bem interessante quando falamos de desenvolvimento em C
é saber onde está as APIs do sistema e detalhes claro que você
pode simplesmente abrir “/usr/include” e ver as headers a olho
nu , mais uma forma mais nobre de se informar é usar o
pkg-config“, exemplo

 $ pkg-config --list-all

uma lista das API instaladas irá surgir logo a frente informação
sobre as funções da mesma.

se quisermos saber se a libcurl foi instalada

 $ pkg-config --list-all | grep curl 

ver versão da header

 $ pkg-config --print-provides libcurl 

ver o último log da libcurl para depuração,algumas pkg pedem “*-dbg
no caso da libcurl não pede…

 $ pkg-config --debug libcurl | tail

exemplo referenciando as libs do GTK caso queira fazer uma aplicação
usando gtk,para não ter que escrever lib por lib com argumento “-l”

 $ gcc -o code code.c `pkg-config --cflags --libs gtk+-2.0` 

apenas mostrando a referencias das bibliotecas

 $ pkg-config --cflags gtk+-2.0

mais informações “man pkg-config

 
3 Comentários

Publicado por em outubro 27, 2011 em Linguagem C