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)
  • Limonene@lemmy.world
    link
    fedilink
    arrow-up
    4
    ·
    2 hours ago

    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 the printf, and only scanning half the pointer with the scanf. The correct data type to be using for this is uintptr_t , which is the same as uint32_t on a 32-bit system, and the same as uint64_t on a 64-bit system.

    Try changing the type of addr to uintptr_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.

    • LalSalaamComrade@lemmy.mlOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      edit-2
      1 hour ago

      This worked for me - I think %p fixed the issue of incorrect representation, as well as input. I also tried unsigned long int, which works in place of uintptr_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;
      }
      
  • huf [he/him]@hexbear.net
    link
    fedilink
    English
    arrow-up
    2
    ·
    2 hours ago

    i dont think pointers are the same size as your int. you’re on 64bit, arent you? so all this code is broken.

    • huf [he/him]@hexbear.net
      link
      fedilink
      English
      arrow-up
      3
      ·
      2 hours ago

      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