cross-posted from: https://lemmy.ml/post/21033409
In the book authored by K.N.King, there’s this example:
viewmemory.c
/* Allows the user to view regions of computer memory */ #include <stdio.h> #include <ctype.h> typedef unsigned char BYTE; int main(void) { unsigned int addr; int i, n; BYTE *ptr; printf("Address of main function: %x\n", (unsigned int) main); printf("Address of addr variable: %x\n", (unsigned int) &addr); printf("\nEnter a (hex) address: "); scanf("%x", &addr); printf("Enter number of bytes to view: "); scanf("%d", &n); printf("\n"); printf(" Address Bytes Characters\n"); printf(" ------- ------------------------------- ----------\n"); ptr = (BYTE *) addr; for (; n > 0; n -= 10) { printf("%8X ", (unsigned int) ptr); for (i = 0; i < 10 && i < n; i++) printf("%.2X ", *(ptr + i)); for (; i < 10; i++) printf(" "); printf(" "); for (i = 0; i < 10 && i < n; i++) { BYTE ch = *(ptr + i); if (!isprint(ch)) ch = '.'; printf("%c", ch); } printf("\n"); ptr += 10; } return 0; }
For some reason, when I try to enter
addr
variable address as the parameter, it has a segmentation fault error. However, in the book’s example and the screenshot from this site in Hangul, there’s no such error?When I try using
gdb
to check the issue, here’s what I get:gdb
$ gdb ./a.out --silent Reading symbols from ./a.out... (gdb) run Starting program: /home/<username>/Desktop/c-programming-a-modern-approach/low-level-programming/a.out [Thread debugging using libthread_db enabled] Using host libthread_db library "/gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libthread_db.so.1". Address of main function: 401166 Address of addr variable: ffffd678 Enter a (hex) address: ffffd678 Enter number of bytes to view: 64 Address Bytes Characters ------- ------------------------------- ---------- Program received signal SIGSEGV, Segmentation fault. 0x000000000040123a in main () at viewmemory.c:31 warning: Source file is more recent than executable. 31 printf ("%.2X ", *(ptr + i)); (gdb)
What is going on? By the way, I am using Guix, if that matters in any way. Here’s the output for
ldd
:ldd
$ ldd ./a.out linux-vdso.so.1 (0x00007ffecdda9000) libgcc_s.so.1 => /gnu/store/w0i4fd8ivrpwz91a0wjwz5l0b2ralj16-gcc-11.4.0-lib/lib/libgcc_s.so.1 (0x00007fcd2627a000) libc.so.6 => /gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libc.so.6 (0x00007fcd2609c000)
i dont think pointers are the same size as your int. you’re on 64bit, arent you? so all this code is broken.
Don’t you have to reserve the memory before showing it?
i think the intention is to look at the stack itself. which could work, if the pointers werent hopelessly mangled by being cast from an 8byte pointer type to a 4byte integer type…
unless this machine really is 32bit
Looks like this program is really old. It appears to be designed for a 32-bit system, the way it casts between
unsigned int
and pointers.unsigned int
is probably 32-bit even on your 64-bit system, so you’re only printing half the pointer with theprintf
, and only scanning half the pointer with thescanf
. The correct data type to be using for this isuintptr_t
, which is the same asuint32_t
on a 32-bit system, and the same asuint64_t
on a 64-bit system.Try changing the type of
addr
touintptr_t
, and change lines 14-17 to this:printf("Address of main function: %p\n", (void *) &main); printf("Address of addr variable: %p\n", (void *) &addr); printf("\nEnter a (hex) address: "); scanf("%p", &addr);
You may have to include
<stdint.h>
. These changes should make the code portable to any 32-bit or 64-bit architecture.This worked for me - I think
%p
fixed the issue of incorrect representation, as well as input. I also triedunsigned long int
, which works in place ofuintptr_t
, but I’m assuming that it isn’t portable.Resolved code snippet
/* Allows the user to view regions of computer memory */ #include <ctype.h> #include <stdint.h> #include <stdio.h> typedef unsigned char BYTE; int main (void) { uintptr_t addr; int i, n; BYTE *ptr; printf ("Address of main function: %p\n", (void *) &main); printf ("Address of addr variable: %p\n", (void *) &addr); printf ("\nEnter a (hex) address: "); scanf ("%p", &addr); printf ("Enter number of bytes to view: "); scanf ("%d", &n); printf ("\n"); printf (" Address Bytes Characters\n"); printf (" ------- ------------------------------- ----------\n"); ptr = (BYTE *) addr; for (; n > 0; n -= 10) { printf ("%8X ", (uintptr_t) ptr); for (i = 0; i < 10 && i < n; i++) printf ("%.2X ", *(ptr + i)); for (; i < 10; i++) printf (" "); printf (" "); for (i = 0; i < 10 && i < n; i++) { BYTE ch = *(ptr + i); if (!isprint (ch)) ch = '.'; printf ("%c", ch); } printf ("\n"); ptr += 10; } return 0; }