<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>NotANumber</title>
	<atom:link href="http://www.pedro.kiefer.com.br/feed" rel="self" type="application/rss+xml" />
	<link>http://www.pedro.kiefer.com.br</link>
	<description>Rambles of an Engineer</description>
	<lastBuildDate>Sun, 04 Jul 2010 14:56:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Ponteiros!</title>
		<link>http://www.pedro.kiefer.com.br/2010/07/ponteiros</link>
		<comments>http://www.pedro.kiefer.com.br/2010/07/ponteiros#comments</comments>
		<pubDate>Sun, 04 Jul 2010 05:26:01 +0000</pubDate>
		<dc:creator>Pedro Kiefer</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[C pointers]]></category>
		<category><![CDATA[diversão]]></category>
		<category><![CDATA[ponteiros]]></category>

		<guid isPermaLink="false">http://www.pedro.kiefer.com.br/?p=224</guid>
		<description><![CDATA[Outro dia no trabalho resolvemos brincar com ponteiros, não que o código que resultou da brincadeira seja algo bom, mas foi divertido. Basicamente tinhamos uma função que traduzia uma string interna passada para a string que utilizariamos em tela, software foi crescendo e mais traduções eram necessárias para a mesma string. Então aos exemplos, do [...]]]></description>
			<content:encoded><![CDATA[<p>Outro dia no trabalho resolvemos brincar com ponteiros, não que o código que resultou da brincadeira seja algo bom, mas foi divertido. Basicamente tinhamos uma função que traduzia uma string interna passada para a string que utilizariamos em tela, software foi crescendo e mais traduções eram necessárias para a mesma string.</p>
<p>Então aos exemplos, do que tinhamos, da brincadeira que fizemos com os ponteiros e o que seria a melhor solução para o código. Antes algumas definições, a estrutura que contém as strings é a seguinte, basicamente um mapa 1 pra n:</p>
<pre class="brush: c">
enum {
	KERNEL = 1,
	WEB,
	CLI
};

struct test {
	int idx;
	char *kernel;
	char *web;
	char *cli;
};

struct test example[] = {
	{.idx = 0, .kernel = &quot;eth0&quot;, .web = &quot;Ethernet 0&quot;, .cli = &quot;ethernet0&quot; },
	{.idx = 1, .kernel = &quot;eth1&quot;, .web = &quot;Ethernet 1&quot;, .cli = &quot;ethernet1&quot; },
	{.idx = 2, .kernel = &quot;eth2&quot;, .web = &quot;Ethernet 2&quot;, .cli = &quot;ethernet2&quot; },
	{.idx = 3, .kernel = NULL, .web = NULL, .cli = NULL}
};
</pre>
<p>A versão original da função que procurava pela string correta era algo parecido com:</p>
<pre class="brush: c">
char *get_str_for_v1(const char *eth, enum str_type type)
{
	char *rtn = NULL;
	int i;

	switch (type) {
	case KERNEL:
		for (i = 0; i &lt; sizeof (example); i++) {
			if (strcmp(eth, example[i].kernel) == 0) {
				rtn = example[i].kernel;
				break;
			}
		}
		break;
	case WEB:
		for (i = 0; i &lt; sizeof (example); i++) {
			if (strcmp(eth, example[i].kernel) == 0) {
				rtn = example[i].web;
				break;
			}
		}
		break;
	case CLI:
		for (i = 0; i &lt; sizeof (example); i++) {
			if (strcmp(eth, example[i].kernel) == 0) {
				rtn = example[i].cli;
				break;
			}
		}
		break;
	}

	return rtn;
}
</pre>
<p>O que é obviamente muito feio! Com excesso de código repetido, péssimo de ler e dar manutenção. Vendo esse código propus o desafio de escrever a mesma função com um <code>for</code> só. Meu colega de trabalho resolveu usar ponteiros pra resolver isso, calculando o offset de cada um dos membros da estrutura e recuperando o ponteiro da string a partir do offset. Claro, isso parece muito simples de se fazer&#8230; mas na hora de escrever o código, demorou bem mais do que imaginavamos, mas foi bastante divertido entender como funcionam os casts em C.</p>
<p>O resultado foi o seguinte código, as macros eu adicionei para facilitar a leitura do código, mais sobre elas daqui um pouco&#8230;</p>
<pre class="brush: c">
#define member_offset(type, member) \
			((unsigned long)(&amp;((type *)0)-&gt;member))
#define get_member_by_offset(ptr, type, offset) \
			((type *)((void *)(ptr) + offset))

char *get_str_for_pointer_fun(const char *eth, enum str_type type)
{
	int i;
	unsigned long offset;

	switch(type) {
	case KERNEL:
		offset = member_offset(struct test, kernel);
		break;
	case WEB:
		offset = member_offset(struct test, web);
		break;
	case CLI:
		offset = member_offset(struct test, cli);
		break;
	}

	for (i = 0; i &lt; sizeof (example); i++) {
		if (strcmp(eth, example[i].kernel) == 0) {
			return *get_member_by_offset(&amp;example[i], char *, offset);
		}
	}

	return NULL;
}
</pre>
<p>Com certeza não é a melhor implementação possível, talvez seja a mais complexa de se entender, especialmente se não for utilizada uma macro para esconder a implementação. Mas é uma implementação divertida, ou pelo menos foi divertido tentar achar a combinação correta de ponteiros para gerá-la.</p>
<p>E finalmente o código que eu julgo o mais aceitável:</p>
<pre class="brush: c">
char *get_str_for_v2(const char *eth, enum str_type type)
{
	int i;

	for (i = 0; i &lt; sizeof (example); i++) {
		if (strcmp(eth, example[i].kernel) == 0) {
			switch (type) {
			case KERNEL:
				return example[i].kernel;
			case WEB:
				return example[i].web;
			case CLI:
				return example[i].cli;
			}
		}
	}

	return NULL;
}
</pre>
<h2>Macros</h2>
<p>Bom, disse que ia explicar o funcionamento das duas macros utilizadas, então recapitulando elas:</p>
<pre class="brush: c">
#define member_offset(type, member) \
			((unsigned long)(&amp;((type *)0)-&gt;member))

#define get_member_by_offset(ptr, type, offset) \
			((type *)((void *)(ptr) + offset))
</pre>
<p>A macro <code>member_offset</code> calcula o offset de um membro qualquer de um estrutura. Para fazer isso, ela dá um cast para um ponteiro do tipo da estrutura requerida ao valor 0. O que parece estranho a princípio, mas faz todo o sentido! Do ponteiro para zero até o membro requerido da estrutura existem os <em>n</em> bytes que representam o offset em memória do início da estrutura até o membro.</p>
<p>Munido do valor do offset, podemos então recuperar a estrutura que se encontra naquele offset utilizando a macro <code>get_member_by_offset</code>. Obviamente é necessário sabermos qual o tipo de dado que se encontra naquele offset! Então a partir do ponteiro (endereço) da estrura que queremos acessar podemos somar o offset do membro requerido. Mas só somar o offset não resolve, é necessário dar os casts apropriados. </p>
<p>Como queremos um que o endereço calculado (ponteiro original + offset) seja um ponteiro, é necessário indicar isto ao compilador, colocando um * no cast do cálculo. Além disso, é necessário indicar que tipo de ponteiro estamos recuperando naquele endereço, portanto o cast vira <code>(type *)</code>.  No exemplo, o cast é <code>(char **)</code> indicando corretamente que naquele endereço encontra-se uma string.</p>
<p>Esse mesmo método de recuperar um membro de uma estrutura é utilizado na implementação de listas no kernel do linux. A macro definida é um pouco diferente, uma vez que ela realiza estas duas operações de uma só vez, mas a explicação do seu funcionamento é a mesma! Segue a sua implementação:</p>
<pre class="brush: c">
#define list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&amp;((type *)0)-&gt;member)))
</pre>
<p>Basicamente o que este código faz é recuperar o ponteiro para a estrutura a partir de um membro qualquer dela. No caso das listas, o membro utilizado para recuperar a estrutura original é o <code>struct list_head</code>. Com isso, é possível utilizar diversos <code>struct list_head</code> numa mesma estrutura, adicionando ou não a estrutura alocada a uma das listas.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pedro.kiefer.com.br/2010/07/ponteiros/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fundação Iberê</title>
		<link>http://www.pedro.kiefer.com.br/2010/06/fundacao-ibere</link>
		<comments>http://www.pedro.kiefer.com.br/2010/06/fundacao-ibere#comments</comments>
		<pubDate>Sun, 20 Jun 2010 23:01:42 +0000</pubDate>
		<dc:creator>Pedro Kiefer</dc:creator>
				<category><![CDATA[Photo]]></category>
		<category><![CDATA[Fotos]]></category>
		<category><![CDATA[Fundação Iberê]]></category>
		<category><![CDATA[Photos]]></category>

		<guid isPermaLink="false">http://www.pedro.kiefer.com.br/?p=217</guid>
		<description><![CDATA[Outro dia me dei conta de que nunca tinha tirado uma foto da Fundação Iberê, apesar de ter acompanhado a obra de perto &#8211; vendo meu pai organizar o livro sobre o projeto e construção; indo à obra com o Fábio, que fotografou todo o processo da construção. Então resolvi que na minha próxima ida [...]]]></description>
			<content:encoded><![CDATA[<p>Outro dia me dei conta de que nunca tinha tirado uma foto da Fundação Iberê, apesar de ter acompanhado a obra de perto &#8211; vendo meu pai organizar o livro sobre o projeto e construção; indo à obra com o Fábio, que fotografou todo o processo da construção. Então resolvi que na minha próxima ida iria tirar algumas fotos. </p>
<p>Também aproveitei a ida pra ver a exposição da Mira Schendel e do León Ferrari, que realmente vale a pena. Saí de lá com a vontade de ter um trabalho de letraset da Mira, simplesmente genial!</p>
<p>Bom, o resultado das fotos está ai abaixo&#8230; não ficaram o supra-sumo, e também faltou uma foto do paredão de concreto dos fundos que é <strong>muito</strong> legal! Mas na próxima ida eu tiro essa foto!</p>
<p><a href="http://www.flickr.com/photos/pkiefer/4719054138/" class="tt-flickr tt-flickr-Medium" title="Fundação Iberê Camargo"><img class="aligncenter" src="http://farm5.static.flickr.com/4033/4719054138_078f705b1f.jpg" alt="Fundação Iberê Camargo" width="335" height="500" /></a> </p>
<p><a href="http://www.flickr.com/photos/pkiefer/4719046984/" class="tt-flickr tt-flickr-Medium" title="Fundação Iberê Camargo"><img class="aligncenter" src="http://farm5.static.flickr.com/4050/4719046984_5fb883f819.jpg" alt="Fundação Iberê Camargo" width="335" height="500" /></a> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.pedro.kiefer.com.br/2010/06/fundacao-ibere/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Análise Estática com LLVM</title>
		<link>http://www.pedro.kiefer.com.br/2010/06/analise-estatica-com-llvm</link>
		<comments>http://www.pedro.kiefer.com.br/2010/06/analise-estatica-com-llvm#comments</comments>
		<pubDate>Wed, 02 Jun 2010 19:45:11 +0000</pubDate>
		<dc:creator>Pedro Kiefer</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[análise estática]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Clang]]></category>
		<category><![CDATA[LLVM]]></category>
		<category><![CDATA[Static Analysis]]></category>

		<guid isPermaLink="false">http://www.pedro.kiefer.com.br/?p=152</guid>
		<description><![CDATA[LLVM é uma coleção de tecnologias de compiladores (ou algo assim, é que eles usam para se autodefinir), mas esse não é o ponto mais interessante &#8211; apesar de existirem diversos subprojetos bastante interessantes, a parte mais legal do LLVM é o subprojeto Clang Static Analyzer &#8211; ok, ele é parte do subprojeto Clang na [...]]]></description>
			<content:encoded><![CDATA[<p>LLVM é uma coleção de tecnologias de compiladores (ou algo assim, é que eles usam para se <a href="http://llvm.org">autodefinir</a>), mas esse não é o ponto mais interessante &#8211; apesar de existirem diversos subprojetos bastante interessantes, a parte mais legal do LLVM é o subprojeto <a href="http://clang-analyzer.llvm.org/">Clang Static Analyzer</a> &#8211; ok, ele é parte do subprojeto <a href="http://clang.llvm.org/">Clang</a> na verdade. O Clang utiliza as tecnologias oferecidas pelo LLVM para implementar um compilador completo, com algumas vantagens é extremamente <a href="http://clang.llvm.org/performance.html">rápido</a> e dá ótimas mensagens de <a href="http://clang.llvm.org/diagnostics.html">erro</a>.</p>
<p>Meu interessante por análise estática surgiu primeiro quando eu ainda brincava de descompilar programas e entender o que eles faziam, afinal, quando se lê um código sem executá-lo estamos fazendo uma análise. Mas cansei de ler ASM, passei a programar mais e fui atrás de algo que fizesse algo parecido com o que eu fazia. Descobri várias ferramentas que fazem algum tipo de análise estática: lint, sparse e o clang. Sim, lint aquele programa velhão que verificava se um código C era bem formado fazia nada mais do que uma análise estática do código &#8211; ok, sem grandes interpretações do que o código fazia. O <a href="https://sparse.wiki.kernel.org/index.php/Main_Page">Sparse</a> é um parser semântico para C, faz mais ou menos a mesma coisa que o lint fazia, mas é um código mais novo, originalmente escrito pelo Linus Torvalds. E finalmente há o Clang&#8230;</p>
<h2>Clang Static Analyzer</h2>
<p>Primeiro passo para testar e usar o Clang é obter os arquivos fonte e compilá-lo, pelo menos não achei uma versão para download (ok, há uma versão para Mac OSX). Há um bom passo-a-passo <a href="http://clang.llvm.org/get_started.html#build">aqui</a>. Em linhas gerais:</p>
<pre>
cd tools
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
cd ..
./configure
make
make install
</pre>
<p>Atualmente o Clang não instala os scripts <code>scan-build</code> e <code>scan-view</code>, então é necessário copiá-los manualmente. Instalei os scripts em <code>$HOME/bin/</code>, pois já tinha esse caminho no meu path. <code>scan-build</code> é a ferramenta responsável por criar o ambiente necessário para executar o Clang. Com a ferramenta instalada é hora de utilizá-la!</p>
<p>Ah, ele também tem um suporte bem legal a Objective-C, tanto para programas para Mac quanto para aplicativos de iPhone / iPad! Mas, ainda não testei essa funcionalidade.</p>
<h2>Usando o Clang</h2>
<p>Precisamos de um código com alguns problemas para testar o clang. Resolvi reutilizar o código do post sobre <a href="?p=150">valgrind</a>. Ok, não é o melhor código para demonstrar as funcionalidades do clang, mas é suficientemente bom. Há quatro bugs naquele código, todos foram corretamente identificados pelo <strong>valgrind</strong>. Quantos desses erros o Clang conseguirá identificar? Usando o scan-build, habilitando verificações experimentais, obtemos:</p>
<pre>
pedro@urubu:~/code$ scan-build --experimental-checks gcc -g -O1 -o valtest valtest.c
valtest.c:13:2: warning: Access out-of-bound array element (buffer overflow)
        x[5] = 'a';
        ^~~~
valtest.c:20:2: warning: Value stored to 'x' is never read
        x = malloc(5 * sizeof(char));
        ^   ~~~~~~~~~~~~~~~~~~~~~~~~
valtest.c:20:4: warning: Allocated memory never released. Potential memory leak.
        x = malloc(5 * sizeof(char));
        ~~^~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.
scan-build: 3 bugs found.
scan-build: Run 'scan-view /tmp/scan-build-2010-06-01-4' to examine bug reports.
</pre>
<p>Dentro de <code>/tmp/scan-build-2010-06-01-4</code> há um relatório em html com cada erro encontrado, basicamente o código fonte anotado. Um dos erros acima gerou o seguinte relatório:</p>
<div id="attachment_e1275506756247" class="wp-caption aligncenter" style="width: 510px"><img src="http://www.pedro.kiefer.com.br/wp-content/uploads/2010/06/clang-report-e1275506756247.png" alt="clang-report" title="clang-report" width="444" height="207" /><p class="wp-caption-text">Exemplo de relatório gerado</p></div>
<p>Resultado, o Clang encontrou três problemas no código, sendo que dois são na mesma linha de código &#8211; gerados pelo mesmo problema. Então dos quatro bugs existentes no código a ferramenta identificou dois&#8230; nada mal para uma ferramenta que só analizou o código fonte! Claro, há outros bugs que a ferramenta irá identificar e o valgrind não. There is no silver bullet, mas várias ferramentas utilizadas em conjunto conseguem aumentar bastante a qualidade do código escrito.</p>
<p>Duas coisas para terminar este post, não utilizei o clang para gerar código, somente para fazer análise do código fonte, mas isso é perfeitamente viável. E para completar, se formos utilizar o Clang junto a um projeto com autotools, fariamos:</p>
<pre>
pedro@urubu:~/code/myproject$ scan-build ./configure
pedro@urubu:~/code/myproject$ scan-build make
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.pedro.kiefer.com.br/2010/06/analise-estatica-com-llvm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Valgrind &amp; Embedded Linux</title>
		<link>http://www.pedro.kiefer.com.br/2010/05/valgrind-embedded-linux</link>
		<comments>http://www.pedro.kiefer.com.br/2010/05/valgrind-embedded-linux#comments</comments>
		<pubDate>Tue, 01 Jun 2010 02:28:44 +0000</pubDate>
		<dc:creator>Pedro Kiefer</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[cross compiling]]></category>
		<category><![CDATA[embedded linux]]></category>
		<category><![CDATA[powerpc]]></category>
		<category><![CDATA[ppc32]]></category>
		<category><![CDATA[valgrind]]></category>

		<guid isPermaLink="false">http://www.pedro.kiefer.com.br/?p=187</guid>
		<description><![CDATA[Como continuação ao último post, resolvi testar o comportamento do valgrind em um sistema embarcado. Primeiro passo obviamente é ter um ambiente de desenvolvimento apropriado, isto é, um toolchain para cross-compilar os pacotes necessários, a glibc compilada para a plataforma em questão, etc. A maioria dos fabricantes de processadores para arquiteturas embarcadas fornecem um pacote [...]]]></description>
			<content:encoded><![CDATA[<p>Como continuação ao último <a href="?p=150">post</a>, resolvi testar o comportamento do <strong>valgrind</strong> em um sistema embarcado. Primeiro passo obviamente é ter um ambiente de desenvolvimento apropriado, isto é, um toolchain para cross-compilar os pacotes necessários, a glibc compilada para a plataforma em questão, etc. A maioria dos fabricantes de processadores para arquiteturas embarcadas fornecem um pacote contendo toda a toolchain necessária para compilar para a arquitetura em questão. Para escrever este blog eu utilizei o toolchain de powerpc fornecido pela <a href="http://www.freescale.com">Freescale</a>.</p>
<p>Começei por instalar o pacote em um local conhecido digamos <code>$HOME/toolchains/powerpc-linux-gnu</code>, ajustei minha variável <code>$PATH</code> de modo que fosse possível encontrar os compiladores e ferramentas da toolchain &#8211; algo como <code>export PATH=$PATH:$HOME/toolchains/powerpc-linux-gnu/bin</code>, isto irá mudar dependendo do toolchain usado e onde ele foi instalado.</p>
<p>Com as ferramentas instaladas, hora de conseguir o source do valgrind! Primeiro baixei o tarball (versão 3.5) do site do valgrind, mas logo descobri que havia um problema com umas macros usadas que não permitiam cross-compilar o pacote &#8211; vide <a href="https://bugs.kde.org/show_bug.cgi?id=204843">bug</a>, que já está corrigido, mas não liberaram um pacote novo. Bom, hora de baixar o código fonte do <a href="http://www.valgrind.org/downloads/repository.html">SVN</a>! Vamos colocar o código dentro do diretório <code>pkgs</code> do projeto <code>my-project</code>.</p>
<pre>
cd $HOME/my-project/pkgs/
svn co svn://svn.valgrind.org/valgrind/trunk valgrind
</pre>
<p>Feito isso, hora de compilar o <strong>valgrind</strong>! Antes um aviso para os navegantes: o valgrind coloca o caminho <code>$PREFIX/bin</code> hardcoded no binário gerado, e utiliza esse caminho para achar as diversas ferramentas geradas (callgrind, memcheck, etc). Obviamente eu não percebi isso na primeira vez que compilei, mas depois de umas tentativas consegui acertar os valores corretos. A melhor solução é deixar o <code>$PREFIX</code> apontando para <code>/usr</code> como em qualquer instalação normal, compilar normalmente o código e na hora de instalar usar a variável <code>DESTDIR</code> para apontar o diretório correto para realizar a instalação. No meu caso isso é necessário, pois quero instalar num diretório que será montado por <strong>NFS</strong> no dispositivo embarcado (<code>$HOME/my-project/rootfs</code>). O -j4 é por que eu sou impaciente e tenho <em>cores</em> demais na máquina. </p>
<pre>
cd valgrind
./configure --host=powerpc-linux-gnu --prefix=/usr --disable-tls
make -j4
make install DESTDIR=$HOME/my-project/rootfs
</pre>
<p>Com isso temos o <strong>valgrind</strong> instalado no diretório raíz utilizado pelo sistema embarcado que queremos testar! Hora de bootar o sistema, esperar ele carregar e fire it away! Abaixo um exemplo do valgrind rodando em um sistema embarcado.</p>
<pre>
-sh-4.0# valgrind test
==1653== Memcheck, a memory error detector
==1653== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==1653== Using Valgrind-3.6.0.SVN and LibVEX; rerun with -h for copyright info
==1653== Command: test
==1653==
Prompt>exit
==1653== Invalid read of size 1
==1653==    at 0x10007F88: test_execute (in /bin/test)
==1653==    by 0x10009A23: main (in /bin/test)
==1653==  Address 0x403e0fd is 0 bytes after a block of size 5 alloc'd
==1653==    at 0xFFBA4B0: malloc (vg_replace_malloc.c:236)
==1653==    by 0xFF5FA2F: xmalloc (in /lib/libreadline.so.6.0)
==1653==    by 0xFF419CB: readline_internal_teardown (in /lib/libreadline.so.6.0)
==1653==    by 0xFF41D1B: readline (in /lib/libreadline.so.6.0)
==1653==    by 0x100098AB: main (in /bin/test)
==1653==
==1653==
==1653== HEAP SUMMARY:
==1653==     in use at exit: 24,589 bytes in 145 blocks
==1653==   total heap usage: 229 allocs, 84 frees, 53,399 bytes allocated
==1653==
==1653== LEAK SUMMARY:
==1653==    definitely lost: 0 bytes in 0 blocks
==1653==    indirectly lost: 0 bytes in 0 blocks
==1653==      possibly lost: 0 bytes in 0 blocks
==1653==    still reachable: 24,589 bytes in 145 blocks
==1653==         suppressed: 0 bytes in 0 blocks
==1653== Rerun with --leak-check=full to see details of leaked memory
==1653==
==1653== For counts of detected and suppressed errors, rerun with: -v
==1653== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 3)
</pre>
<p>Só para completar, o <strong>valgrind</strong> ajuda bastante a achar os problemas no software, mas lembre-se que um sistema embarcado possuiu outras limitações, como pouca memória, processador com clock baixo, etc. Essas limitações se refletem no desempenho do valgrind, o software ficará bastante lento, algumas flags do valgrind não funcionarão &#8211; no meu caso foi por falta de memória, precisaria de mais do que os 64M de RAM disponíveis para utilizar o <code>--track-origins</code> (Ah, o manual do <strong>valgrind</strong> informa que é necessário no mínimo 100M de RAM para este parâmetro funcionar!).</p>
<p>Happy Hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pedro.kiefer.com.br/2010/05/valgrind-embedded-linux/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Valgrind</title>
		<link>http://www.pedro.kiefer.com.br/2010/05/valgrind</link>
		<comments>http://www.pedro.kiefer.com.br/2010/05/valgrind#comments</comments>
		<pubDate>Sun, 30 May 2010 19:35:05 +0000</pubDate>
		<dc:creator>Pedro Kiefer</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[leaks]]></category>
		<category><![CDATA[memcheck]]></category>
		<category><![CDATA[memory leaks]]></category>
		<category><![CDATA[valgrind]]></category>

		<guid isPermaLink="false">http://www.pedro.kiefer.com.br/?p=150</guid>
		<description><![CDATA[Valgrind tem esse nome estranho mas é a ferramenta que todo o programador deveria ter no seu cinto de utilidades do Batman! O nome provêm da mitologia nórdica e significa a entrada de Valhalla &#8211; wikipédia tem mais explicações. Agora, por que todo programador deve ter essa ferramenta no bat-cinto? A resposta é simples: ela [...]]]></description>
			<content:encoded><![CDATA[<p>Valgrind tem esse nome estranho mas é a ferramenta que todo o programador deveria ter no seu cinto de utilidades do Batman! O nome provêm da mitologia nórdica e significa a entrada de Valhalla &#8211; <a href="http://en.wikipedia.org/wiki/Valhalla">wikipédia</a> tem mais explicações. Agora, por que todo programador deve ter essa ferramenta no bat-cinto? A resposta é simples: ela instrumenta o aplicativo em tempo de execução e identifica leaks de memória (memória que foi alocada mas nunca liberada), uso inválidos de ponteiros, variáveis não inicializadas, múltiplos frees na mesma váriavel, etc. Se isso não bastasse, há ainda outros backends que identificam chamadas de função, uso de cache, memória alocada, etc, e obviamente você pode escrever o seu próprio backend!</p>
<p>O foco deste post é mostrar o uso do backend memcheck para solucionar problemas de memória. Necessitamos, para isso, de um código com alguns bugs. Sabemos que um bom programador, lendo este código, identificará todos os problemas que existem nele, mas muitas vezes estes mesmo problemas surgem de forma escondida no código, o que torna necessário o uso de uma ferramenta para ajudar a identificá-los.</p>
<p>O código a seguir exercita a maior parte das funcionalidades do backend memcheck &#8211; o padrão do <strong>valgrind</strong>. Compile o código executando a seguinte linha, observe que o <strong>gcc</strong> é chamado com a flag <code>-Wall</code> que habilita diversos <em>warnings</em> durante a compilação, apesar disso, o código deve compilar sem nenhum problema.</p>
<pre>
gcc -Wall -O1 -g -o valtest valtest.c
</pre>
<pre class="brush: c">
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

struct uninit {
	char *x;
	char *y;
};

void heap(void)
{
	char *x;
	x = malloc(5 * sizeof(char));
	x[5] = &#039;a&#039;;
	free(x);
}

void leak(void)
{
	char *x;
	x = malloc(5 * sizeof(char));
}

void uninitialized(void)
{
	struct uninit *u;
	u = malloc(sizeof(struct uninit));
	if (u-&gt;y == 0) {
		printf(&quot;y is 0\n&quot;);
	}
	free(u);
}

char * double_free(void)
{
	char *x;
	x = malloc(5 * sizeof(char));
	free(x);
	return x;
}

int main(int argc, char *argv[])
{
	char *x;

	printf(&quot;Calling heap()\n&quot;);
	heap();

	printf(&quot;Calling leak()\n&quot;);
	leak();

	printf(&quot;Calling uninitialized()\n&quot;);
	uninitialized();

	printf(&quot;Calling double_free()\n&quot;);
	x = double_free();
	free (x);

	return 0;
}
</pre>
<p>Se executarmos este código, ainda sem utilizar o <strong>valgrind</strong>, obteremos um erro por causa do duplo <em>free</em>. A saída da execução será algo parecido com as linhas abaixo, talvez inclua um backtrace ou mais alguma informação, mas isso depende da libc utilizada. Repare que a mensagem de erro não indica onde ocorreu o problema no código.</p>
<pre>
pedro@urubu:~/code$ ./valtest
Calling heap()
Calling leak()
Calling uninitialized()
y is 0
Calling double_free()
*** glibc detected *** ./valtest: double free or corruption (fasttop): 0x08b09028 ***
</pre>
<h2>Let the Bug Hunting begin!</h2>
<p>Sabemos que existe um problema com o código, temos uma vaga idéia de onde ele ocorre &#8211; depois da função <code>double_free()</code>, mas há mais problemas no código e nenhum deles foi reportado durante a execução. Hora de usar o <strong>valgrind</strong>! Executando a seguinte linha, obteremos um relatório dos erros encontrados pelo valgrind. Abreviei a saída gerada pelo <strong>valgrind</strong> para mostrar justamente o relatório de erros encontrados.</p>
<pre>
pedro@urubu:~/code$ valgrind ./valtest
==13586== Memcheck, a memory error detector
==13586== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==13586== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==13586== Command: ./valtest
==13586==
<strong>...</strong>
==13586== HEAP SUMMARY:
==13586==     in use at exit: 5 bytes in 1 blocks
==13586==   total heap usage: 4 allocs, 4 frees, 23 bytes allocated
==13586==
==13586== LEAK SUMMARY:
==13586==    definitely lost: 5 bytes in 1 blocks
==13586==    indirectly lost: 0 bytes in 0 blocks
==13586==      possibly lost: 0 bytes in 0 blocks
==13586==    still reachable: 0 bytes in 0 blocks
==13586==         suppressed: 0 bytes in 0 blocks
==13586== Rerun with --leak-check=full to see details of leaked memory
==13586==
==13586== For counts of detected and suppressed errors, rerun with: -v
==13586== Use --track-origins=yes to see where uninitialised values come from
==13586== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 13 from 8 )
</pre>
<p>A ferramenta encontrou 3 erros em 3 contextos diferentes e 5 bytes de memória alocada. É claro que existe alguns bugs neste código! No texto de saída há ainda a sugestão do uso das flags <code>--leak-check=full</code> e <code>-v</code>. Vamos rodar novamente o <strong>valgrind</strong> com estes dois parâmetros antes de chamar o <code>valtest</code>. O número de mensagens aumenta bastante, mas dá novos indicativos do que está acontecendo de errado no código.</p>
<h3>Heap overrun</h3>
<p>O primeiro erro apresentado pela ferramenta é no método<code>heap()</code>, meus grifos:</p>
<pre>Calling heap()
--13590-- REDIR: 0x40a7f40 (malloc) redirected to 0x4024e9b (malloc)
==13590== Invalid write of size 1
<strong>==13590==    at 0x80484FC: heap (valtest.c:13)</strong>
==13590==    by 0x804852B: main (valtest.c:46)
==13590==  Address 0x419402d is 0 bytes after a block of size 5 alloc'd
==13590==    at 0x4024F20: malloc (vg_replace_malloc.c:236)
<strong>==13590==    by 0x80484FB: heap (valtest.c:12)</strong>
==13590==    by 0x804852B: main (valtest.c:46)
==13590==
</pre>
<p>Isto indica que tentou-se escrever 1 byte após os 5 bytes alocados, se olharmos o código isto fica bastante claro! Alocamos 5 bytes para a variável <strong>x</strong>, isto em um array significa os índices entre 0 e 4. Na linha <strong>13</strong> do código tentamos escrever na posição 5, que é uma área de memória além do espaço alocado. A saída da ferramenta ainda nos indica em que lugar no código a memória que está sendo utilizada foi alocada, no caso na linha <strong>12</strong>.</p>
<p>Com isso podemos arrumar o primeiro bug do código, acertando o índice utilizado na linha 13 para ser um valor entre 0 e 4. One down, three to go!</p>
<pre class="brush: c">
void heap(void)
{
	char *x;
	x = malloc(5 * sizeof(char));
	x[0] = &#039;a&#039;;
	free(x);
}
</pre>
<h3>Uninitialized value</h3>
<p>O próximo erro apresentado é do uso de uma variável não inicializada e é apresentado pelo <strong>valgrind</strong> da seguinte forma. Repare que a função <code>leak()</code> foi executada e não apresentou nenhum erro, mas como veremos a ferramenta identificou o erro que acontece na função.</p>
<pre>
Calling leak()
Calling uninitialized()
==13590== Conditional jump or move depends on uninitialised value(s)
==13590==    at 0x80484B2: uninitialized (valtest.c:27)
==13590==    by 0x804855D: main (valtest.c:52)
==13590==
y is 0
</pre>
<p>Olhando a linha 27, conforme indicado pelo valgrind, não parece ter nada de errado com o teste realizado ali. Se olharmos as linhas anteriores fica claro que a estrutura u foi alocada, mas que seus valores nunca foram inicializados e dependendo da implementação do <code>malloc</code> os valores dos membros de uma estrutura não serão nulos. Alterando o código da função <code>uninitialized</code> para que os valores de <code>x</code> e <code>y</code> sejam inicializados resolve este problema.</p>
<pre class="brush: c">
void uninitialized(void)
{
	struct uninit *u;
	u = malloc(sizeof(struct uninit));
	u-&gt;x = NULL;
	u-&gt;y = NULL;

	if (u-&gt;y == 0) {
		printf(&quot;y is 0\n&quot;);
	}
	free(u);
}
</pre>
<h3>Double free</h3>
<p>O próximo problema já foi apresentado pela própria libc, mas não tinhamos um indicativo preciso do local no código onde ocorreu o erro. O <strong>valgrind</strong> nos fornece este dado!</p>
<pre>Calling double_free()
==13590== Invalid free() / delete / delete[]
==13590==    at 0x4024B3A: free (vg_replace_malloc.c:366)
<strong>==13590==    by 0x804857E: main (valtest.c:56)</strong>
==13590==  Address 0x41940d0 is 0 bytes inside a block of size 5 free'd
==13590==    at 0x4024B3A: free (vg_replace_malloc.c:366)
<strong>==13590==    by 0x8048490: double_free (valtest.c:37)</strong>
==13590==    by 0x8048576: main (valtest.c:55)
==13590==
</pre>
<p>A ferramenta indica onde ocorreu o segundo free, linha 56, como também onde está o primeiro, linha 37! Olhando o código percebemos que o free da linha 37 é desnecessário, pois queremos retornar um ponteiro para a memória alocada pela função. Removendo esta linha, a função <code>double_free</code> fica:</p>
<pre class="brush: c">
char * double_free(void)
{
	char *x;
	x = malloc(5 * sizeof(char));
	return x;
}
</pre>
<h3>Leak</h3>
<p>O último problema apresentado pelo código é uma área de memória alocada e nunca liberada. Durante a execução do programa, este problema não é manifestado, somente quando finalizamos o programa é que a ferramenta retorna uma relatório identificando que áreas de memória foram usadas e nunca liberadas.</p>
<pre>==13590== HEAP SUMMARY:
==13590==     in use at exit: 5 bytes in 1 blocks
==13590==   total heap usage: 4 allocs, 4 frees, 23 bytes allocated
==13590==
==13590== Searching for pointers to 1 not-freed blocks
==13590== Checked 56,484 bytes
==13590==
==13590== 5 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13590==    at 0x4024F20: malloc (vg_replace_malloc.c:236)
<strong>==13590==    by 0x80484E7: leak (valtest.c:20)</strong>
==13590==    by 0x8048544: main (valtest.c:49)
</pre>
<p>Analisando a linha 20, vemos que uma área de memória é alocada e o método acaba logo em seguida, sem retornar o ponteiro alocado (para que outra função utilize e libere a memória, por exemplo) ou liberar a memória. Portando estamos vazando essa memória! Se essa função for chamadas diversas vezes durante a execução do programa ocuparemos muita mais memória do que necessitamos, e dependendo do sistema podemos esgotar a memória disponível (pense em um sistema embarcado com 8M de ram, ou menos). É necessário liberar a memória, então:</p>
<pre class="brush: c">
void leak(void)
{
	char *x;
	x = malloc(5 * sizeof(char));
	free(x);
}
</pre>
<h2>Conclusão</h2>
<p>Tendo corrigido os 4 problemas que existiam no código, podemos rodar novamente o <strong>valgrind</strong> e desta vez não obteremos nenhum erro!</p>
<pre>
pedro@urubu:~/code$ valgrind --leak-check=full ./valtest-fix
==13845== Memcheck, a memory error detector
==13845== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==13845== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==13845== Command: ./valtest-fix
==13845==
Calling heap()
Calling leak()
Calling uninitialized()
y is 0
Calling double_free()
==13845==
==13845== HEAP SUMMARY:
==13845==     in use at exit: 0 bytes in 0 blocks
==13845==   total heap usage: 4 allocs, 4 frees, 23 bytes allocated
==13845==
==13845== All heap blocks were freed -- no leaks are possible
==13845==
==13845== For counts of detected and suppressed errors, rerun with: -v
==13845== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 8 )
</pre>
<p>Com isso, vimos os principais tipos de erro de memória que o valgrind identifica. Em um código não fictício é mais complexo encontrar o local exato onde ocorrem e por que ocorrem os erros, mas o <strong>valgrind</strong> dá boas indicações. Costumo utilizar o valgrind sempre que acabo de escrever um pedaço de código, que compila sem <em>warnings</em>, mas que não tenho certeza se desaloquei a memória no lugar certo. É boa prática rodar <strong>sempre</strong> o <strong>valgrind</strong> para identificar os mais diversos bugs que existem no seu código. </p>
<p>Happy bug hunting!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pedro.kiefer.com.br/2010/05/valgrind/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.551 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2010-08-05 20:00:36 -->
<!-- Compression = gzip -->