• No se han encontrado resultados

3.3. Resultados

3.3.1. Cuestionario de evaluación de Control Interno

3.3.1.1. Ejecución del Cuestionario del Control Interno

3.3.1.1.1. Cuestionario aplicado al departamento de contabilidad

Thevalgrindprogram can be used to detect some (but not all) common errors in C programs that use pointers and dynamic storage allocation. On the Zoo, you can run valgrindon your program by puttingvalgrindat the start of the command line:

valgrind ./my-program arg1 arg2 < test-input

This will run your program and produce a report of any allocations and de- allocations it did. It will also warn you about common errors like using unitialized memory, dereferencing pointers to strange places, writing off the end of blocks allocated usingmalloc, or failing to free blocks.

You can suppress all of the output except errors using the-qoption, like this: valgrind -q ./my-program arg1 arg2 < test-input

You can also turn on more tests, e.g.

valgrind -q --tool=memcheck --leak-check=yes ./my-program arg1 arg2 < test-input Seevalgrind --helpfor more information about the (many) options, or look

at the documentation athttp://valgrind.org/ for detailed information about what the output means. For some commonvalgrindmessages, see the examples section below.

If you want to runvalgrindon your own machine, you may be able to find a version that works athttp://valgrind.org. Unfortunately, this is only likely to work if you are running a Unix-like operating system. This does include Linux (either on its own or inside Windows Subsystem for Linux) and OSX, but it does

not include stock Windows.

3.4.4.1 Compilation flags You can run valgrind on any program (try valgrind ls); it does not require special compilation. However, the output of valgrindwill be more informative if you compile your program with debugging information turned on using the-gor-g3flags (this is also useful if you plan to watch your program running usinggdb, ).

3.4.4.2 Automated testing Unless otherwise specified, automated testing of your program will be done using the script in /c/cs223/bin/vg; this runs/c/cs223/bin/valgrindwith the--tool=memcheck,--leak-check=yes, and -q options, throws away your program’s output, and replaces it

with valgrind’s output. If you have a program named ./prog, running /c/cs223/bin/vg ./progshould produce no output.

3.4.4.3 Examples of some common valgrind errors Here are some ex- amples ofvalgrindoutput. In each case the example program is compiled with -g3so thatvalgrindcan report line numbers from the source code.

You may also find it helpful to play with this demo program written by the Spring 2018 course staff.

3.4.4.3.1 Uninitialized values Consider this unfortunate program, which attempts to compare two strings, one of which we forgot to ensure was null- terminated:

#include <stdio.h>

int

main(int argc, char **argv) {

char a[2]; a[0] = 'a';

if(!strcmp(a, "a")) { puts("a is \"a\""); }

return 0; }

examples/valgrindErrors/uninitialized.c

Run without valgrind, we see no errors, because we got lucky and it turned out our hand-built string was null-terminated anyway:

$ ./uninitialized a is "a"

Butvalgrindis not fooled: $ valgrind -q ./uninitialized

==4745== Conditional jump or move depends on uninitialised value(s) ==4745== at 0x4026663: strcmp (mc_replace_strmem.c:426)

==4745== by 0x8048435: main (uninitialized.c:10) ==4745==

==4745== Conditional jump or move depends on uninitialised value(s) ==4745== at 0x402666C: strcmp (mc_replace_strmem.c:426)

==4745==

==4745== Conditional jump or move depends on uninitialised value(s) ==4745== at 0x8048438: main (uninitialized.c:10)

==4745==

Here we get a lot of errors, but they are all complaining about the same call to strcmp. Since it’s unlikely thatstrcmp itself is buggy, we have to assume that we passed some uninitialized location into it that it is looking at. The fix is to add an assignmenta[1] = '\0' so that no such location exists.

3.4.4.3.2 Bytes definitely lost Here is a program that callsmalloc but notfree:

#include <stdio.h> #include <stdlib.h>

int

main(int argc, char **argv) { char *s; s = malloc(26); return 0; } examples/valgrindErrors/missing_free.c

With no extra arguments,valgrindwill not look for this error. But if we turn on--leak-check=yes, it will complain:

$ valgrind -q --leak-check=yes ./missing_free

==4776== 26 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==4776== at 0x4024F20: malloc (vg_replace_malloc.c:236)

==4776== by 0x80483F8: main (missing_free.c:9) ==4776==

Here the stack trace in the output shows where the bad block was allocated: inside malloc(specifically the paranoid replacementmalloc supplied byvalgrind), which was in turn called bymain in line 9 of missing_free.c. This lets us go back and look at what block was allocated in that line and try to trace forward to see why it wasn’t freed. Sometimes this is as simple as forgetting to include afree statement anywhere, but in more complicated cases it may be because I somehow lose the pointer to the block by overwriting the last variable that points to it or by embedding it in some larger structure whose components I forget to free individually.

3.4.4.3.3 Invalid write or read operations These are usually operations that you do off the end of a block frommallocor on a block that has already been freed.

An example of the first case: #include <stdio.h> #include <stdlib.h> #include <assert.h>

int

main(int argc, char **argv) { char *s; s = malloc(1); s[0] = 'a'; s[1] = '\0'; puts(s); return 0; } examples/valgrindErrors/invalid_operations.c ==7141== Invalid write of size 1

==7141== at 0x804843B: main (invalid_operations.c:12)

==7141== Address 0x419a029 is 0 bytes after a block of size 1 alloc'd ==7141== at 0x4024F20: malloc (vg_replace_malloc.c:236)

==7141== by 0x8048428: main (invalid_operations.c:10) ==7141==

==7141== Invalid read of size 1

==7141== at 0x4026063: __GI_strlen (mc_replace_strmem.c:284) ==7141== by 0x409BCE4: puts (ioputs.c:37)

==7141== by 0x8048449: main (invalid_operations.c:14)

==7141== Address 0x419a029 is 0 bytes after a block of size 1 alloc'd ==7141== at 0x4024F20: malloc (vg_replace_malloc.c:236)

==7141== by 0x8048428: main (invalid_operations.c:10) ==7141==

An example of the second: #include <stdio.h> #include <stdlib.h> #include <assert.h>

int

{ char *s; s = malloc(2); free(s); s[0] = 'a'; s[1] = '\0'; puts(s); return 0; } examples/valgrindErrors/freed_block.c ==7144== Invalid write of size 1

==7144== at 0x804846D: main (freed_block.c:13)

==7144== Address 0x419a028 is 0 bytes inside a block of size 2 free'd ==7144== at 0x4024B3A: free (vg_replace_malloc.c:366)

==7144== by 0x8048468: main (freed_block.c:11) ==7144==

==7144== Invalid write of size 1

==7144== at 0x8048477: main (freed_block.c:14)

==7144== Address 0x419a029 is 1 bytes inside a block of size 2 free'd ==7144== at 0x4024B3A: free (vg_replace_malloc.c:366)

==7144== by 0x8048468: main (freed_block.c:11) ==7144==

==7144== Invalid read of size 1

==7144== at 0x4026058: __GI_strlen (mc_replace_strmem.c:284) ==7144== by 0x409BCE4: puts (ioputs.c:37)

==7144== by 0x8048485: main (freed_block.c:16) [... more lines of errors deleted ...]

In both cases the problem is that we are operating on memory that is not guaranteed to be allocated to us. For short programs like these, we might get lucky and have the program work anyway. But we still want to avoid bugs like this because we might not get lucky.

How do we know which case is which? If I write off the end of an existing block, I’ll

see something likeAddress 0x419a029 is 0 bytes after a block of size 1 alloc'd, telling me that I am working on an address after a block that is still al-

located. When I try to write to a freed block, the message changes to Address 0x419a029 is 1 bytes inside a block of size 2 free'd, where the free'd part tells me I freed something I probably shouldn’t have. Fixing the first class of bugs is usually just a matter of allocating a bigger block (but don’t just do this without figuring out why you need a bigger block, or you’ll just be introducing random mutations into your code that may cause

other problems elsewhere). Fixing the second class of bugs usually involves figuring out why you freed this block prematurely. In some cases you may need to re-order what you are doing so that you don’t free a block until you are completely done with it.

Documento similar