From 9f8de76123bb91967006b60fae7ed511d57ce9c6 Mon Sep 17 00:00:00 2001 From: Colin Patrick McCabe <cmccabe@alumni.cmu.edu> Date: Sun, 21 Aug 2011 21:22:06 -0400 Subject: [PATCH 1/1] Initial commit Signed-off-by: Colin McCabe <cmccabe@alumni.cmu.edu> --- Makefile | 21 +++ good.c | 12 ++ grindhouse.go | 30 ++++ grindhouse_test.go | 371 ++++++++++++++++++++++++++++++++++++++++++++++++++++ leaky.c | 11 ++ main.go | 71 ++++++++++ 6 files changed, 516 insertions(+), 0 deletions(-) create mode 100644 Makefile create mode 100644 good.c create mode 100644 grindhouse.go create mode 100644 grindhouse_test.go create mode 100644 leaky.c create mode 100644 main.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..31d1a54 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +include $(GOROOT)/src/Make.inc + +package: grindhouse leaky good + +test-clean: clean + rm -f leaky good + +TARG=grindhouse +GOFILES=grindhouse.go \ + main.go +grindhouse: _obj/$(TARG).a $(GOFILES) + $(GC) -I_obj $(GOFILES) + $(LD) -L_obj -o $@ grindhouse.$O + +leaky: leaky.c + $(HOST_CC) -o $@ $< $(CFLAGS) + +good: good.c + $(HOST_CC) -o $@ $< $(CFLAGS) + +include $(GOROOT)/src/Make.pkg diff --git a/good.c b/good.c new file mode 100644 index 0000000..ce661f5 --- /dev/null +++ b/good.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdlib.h> + +int main(void) +{ + int i = 123; + char outs[128]; + char *c = malloc(100); + snprintf(outs, sizeof(outs), "Guess what is in i! It's %d\n", i); + free(c); + return 0; +} diff --git a/grindhouse.go b/grindhouse.go new file mode 100644 index 0000000..39cc54a --- /dev/null +++ b/grindhouse.go @@ -0,0 +1,30 @@ +package grindhouse + +import "bytes" +import "fmt" +import "io" +import "os" +import "xml" + +type ValgrindInfo struct { + Clean bool +} + +type ValgrindOutput struct { + XMLName xml.Name `xml:"valgrindoutput"` + Protocolversion int `xml:"Protocolversion"` +} + +func ParseValgrindXml(rio io.Reader) (*ValgrindInfo, os.Error) { + var valout ValgrindOutput + xml.Unmarshal(rio, &valout) + fmt.Printf("valout.Protocolversion = %d\n", valout.Protocolversion) + + buffer := bytes.NewBufferString("") + xml.Marshal(buffer, valout) + fmt.Printf("outstring = %s\n", string(buffer.Bytes())) + + vinfo := new(ValgrindInfo) + vinfo.Clean = true + return vinfo, nil +} diff --git a/grindhouse_test.go b/grindhouse_test.go new file mode 100644 index 0000000..2db7923 --- /dev/null +++ b/grindhouse_test.go @@ -0,0 +1,371 @@ +package grindhouse + +import "strings" +import "testing" + +const CLEANXML1 = ` +<?xml version="1.0"?> + +<valgrindoutput> + +<protocolversion>4</protocolversion> +<protocoltool>memcheck</protocoltool> + +<preamble> + <line>Memcheck, a memory error detector</line> + <line>Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.</line> + <line>Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info</line> + <line>Command: ./good</line> +</preamble> + +<pid>13206</pid> +<ppid>32361</ppid> +<tool>memcheck</tool> + +<args> + <vargv> + <exe>/usr/bin/valgrind.bin</exe> + <arg>--suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp</arg> + <arg>--xml-file=/tmp/t</arg> + <arg>--xml=yes</arg> + </vargv> + <argv> + <exe>./good</exe> + </argv> +</args> + +<status> + <state>RUNNING</state> + <time>00:00:00:00.038 </time> +</status> + + +<status> + <state>FINISHED</state> + <time>00:00:00:00.363 </time> +</status> + +<errorcounts> +</errorcounts> + +<suppcounts> + <pair> + <count>2</count> + <name>dl-hack3-cond-1</name> + </pair> + <pair> + <count>2</count> + <name>glibc-2.5.x-on-SUSE-10.2-(PPC)-2a</name> + </pair> +</suppcounts> + +</valgrindoutput> +` + +const ERRORXML1 = ` +<?xml version="1.0"?> + +<valgrindoutput> + +<protocolversion>4</protocolversion> +<protocoltool>memcheck</protocoltool> + +<preamble> + <line>Memcheck, a memory error detector</line> + <line>Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.</line> + <line>Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info</line> + <line>Command: ./leaky</line> +</preamble> + +<pid>7673</pid> +<ppid>32361</ppid> +<tool>memcheck</tool> + +<args> + <vargv> + <exe>/usr/bin/valgrind.bin</exe> + <arg>--suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp</arg> + <arg>--xml-file=/tmp/t</arg> + <arg>--xml=yes</arg> + </vargv> + <argv> + <exe>./leaky</exe> + </argv> +</args> + +<status> + <state>RUNNING</state> + <time>00:00:00:00.039 </time> +</status> + +<error> + <unique>0x4</unique> + <tid>1</tid> + <kind>UninitValue</kind> + <what>Use of uninitialised value of size 8</what> + <stack> + <frame> + <ip>0x4E6A76B</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>_itoa_word</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>_itoa.c</file> + <line>195</line> + </frame> + <frame> + <ip>0x4E6B9B8</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vfprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>vfprintf.c</file> + <line>1613</line> + </frame> + <frame> + <ip>0x4E903F1</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vsnprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/libio</dir> + <file>vsnprintf.c</file> + <line>120</line> + </frame> + <frame> + <ip>0x4E75902</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>snprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>snprintf.c</file> + <line>35</line> + </frame> + <frame> + <ip>0x40056D</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + </frame> + </stack> +</error> + +<error> + <unique>0x5</unique> + <tid>1</tid> + <kind>UninitCondition</kind> + <what>Conditional jump or move depends on uninitialised value(s)</what> + <stack> + <frame> + <ip>0x4E6A775</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>_itoa_word</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>_itoa.c</file> + <line>195</line> + </frame> + <frame> + <ip>0x4E6B9B8</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vfprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>vfprintf.c</file> + <line>1613</line> + </frame> + <frame> + <ip>0x4E903F1</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vsnprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/libio</dir> + <file>vsnprintf.c</file> + <line>120</line> + </frame> + <frame> + <ip>0x4E75902</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>snprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>snprintf.c</file> + <line>35</line> + </frame> + <frame> + <ip>0x40056D</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + </frame> + </stack> +</error> + +<error> + <unique>0x6</unique> + <tid>1</tid> + <kind>UninitCondition</kind> + <what>Conditional jump or move depends on uninitialised value(s)</what> + <stack> + <frame> + <ip>0x4E6D928</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vfprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>vfprintf.c</file> + <line>1613</line> + </frame> + <frame> + <ip>0x4E903F1</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vsnprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/libio</dir> + <file>vsnprintf.c</file> + <line>120</line> + </frame> + <frame> + <ip>0x4E75902</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>snprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>snprintf.c</file> + <line>35</line> + </frame> + <frame> + <ip>0x40056D</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + <obj>/lib/libc-2.11.2.so</obj> + <fn>snprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>snprintf.c</file> + <line>35</line> + </frame> + <frame> + <ip>0x40056D</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + <tid>1</tid> + <kind>UninitCondition</kind> + <what>Conditional jump or move depends on uninitialised value(s)</what> + <stack> + <frame> + <ip>0x4E6D928</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vfprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>vfprintf.c</file> + <line>1613</line> + </frame> + <frame> + <ip>0x4E903F1</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vsnprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/libio</dir> + <file>vsnprintf.c</file> + <line>120</line> + </frame> + <frame> + <ip>0x4E75902</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>snprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>snprintf.c</file> + <line>35</line> + </frame> + <frame> + <ip>0x40056D</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + </frame> + </stack> +</error> + +<error> + <unique>0x7</unique> + <tid>1</tid> + <kind>UninitCondition</kind> + <what>Conditional jump or move depends on uninitialised value(s)</what> + <stack> + <frame> + <ip>0x4E6BAA6</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vfprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>vfprintf.c</file> + <line>1613</line> + </frame> + <frame> + <ip>0x4E903F1</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>vsnprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/libio</dir> + <file>vsnprintf.c</file> + <line>120</line> + </frame> + <frame> + <ip>0x4E75902</ip> + <obj>/lib/libc-2.11.2.so</obj> + <fn>snprintf</fn> + <dir>/home/aurel32/eglibc/eglibc-2.11.2/stdio-common</dir> + <file>snprintf.c</file> + <line>35</line> + </frame> + <frame> + <ip>0x40056D</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + </frame> + </stack> +</error> + + +<status> + <state>FINISHED</state> + <time>00:00:00:00.364 </time> +</status> + +<error> + <unique>0x8</unique> + <tid>1</tid> + <kind>Leak_DefinitelyLost</kind> + <xwhat> + <text>100 bytes in 1 blocks are definitely lost in loss record 1 of 1</text> + <leakedbytes>100</leakedbytes> + <leakedblocks>1</leakedblocks> + </xwhat> + <stack> + <frame> + <ip>0x4C244E8</ip> + <obj>/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so</obj> + <fn>malloc</fn> + <dir>/build/buildd-valgrind_3.6.0~svn11254+nmu1-amd64-08RYEm/valgrind-3.6.0~svn11254+nmu1/coregrind/m_replacemalloc</dir> + <file>vg_replace_malloc.c</file> + <line>236</line> + </frame> + <frame> + <ip>0x400548</ip> + <obj>/mnt/e4test/src/grindhouse/leaky</obj> + <fn>main</fn> + </frame> + </stack> +</error> +` + +func expectCleanToStr(e bool) string { + if (e) { + return "clean"; + } + return "dirty"; +} + +func doParseValgrindXml(desc string, xml string, + t *testing.T, expectClean bool) { + vinfo, err := ParseValgrindXml(strings.NewReader(xml)) + if (err != nil) { + t.Errorf("got parse error!") + return + } + if (vinfo.Clean != expectClean) { + t.Errorf("expected %s to be %s, but it was %s!", + desc, expectCleanToStr(expectClean), expectCleanToStr(vinfo.Clean)) + return + } +} + +func TestCleanXml1(t *testing.T) { + doParseValgrindXml("cleanXml1", CLEANXML1, t, true) +} + +func TestErrorXml1(t *testing.T) { + doParseValgrindXml("errorXml1", ERRORXML1, t, false) +} diff --git a/leaky.c b/leaky.c new file mode 100644 index 0000000..5fefa0c --- /dev/null +++ b/leaky.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <stdlib.h> + +int main(void) +{ + int i; + char outs[128]; + char *c = malloc(100); + snprintf(outs, sizeof(outs), "Guess what is in i! It's %d\n", i); + return 0; +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..c3673b1 --- /dev/null +++ b/main.go @@ -0,0 +1,71 @@ +package grindhouse + +import "flag" +import "fmt" +import "os" + +/* + * Grindhouse + * + * Recommended valgrind options: + * valgrind --xml=yes --xml-file=<file> + */ + +func usage() { + fmt.Fprintf(os.Stderr, +`%s: a valgrind XML file analyzer. +This program analyzes valgrind XML output files and summarizes them. + +Usage: %s [opts] [files] +Options: +-h: this help message +`, os.Args[0], os.Args[0]) +} + +var getHelp = flag.Bool("h", false, "See usage") + +func handleFile(filename string) os.Error { + file, err := os.Open(filename) + if (err != nil) { + fmt.Fprintf(os.Stderr, "Failed to open file %s\n", filename) + return err + } + defer file.Close() + vinfo, err := ParseValgrindXml(file) + if (err != nil) { + fmt.Fprintf(os.Stderr, "Failed to parse file %s\n", filename) + return err + } + if !vinfo.Clean { + return os.EAFNOSUPPORT + } + return nil +} + +func main() { + ret := 0 + flag.Usage = usage + flag.Parse() + if (*getHelp) { + usage() + os.Exit(0) + } + filenames := make([]string, flag.NArg()) + for i := 0; i < flag.NArg(); i++ { + filenames[i] = flag.Arg(i) + } + if (flag.NArg() == 0) { + fmt.Fprintf(os.Stderr, "You must give at least one file to open as an argument.") + usage() + os.Exit(1) + } + for i := 0; i < len(filenames); i++ { + if handleFile(filenames[i]) != nil { + ret = 1 + } + } + if (ret != 0) { + fmt.Fprintf(os.Stderr, "Errors were encountered.") + } + os.Exit(ret) +} -- 1.6.6.rc1.39.g9a42