this post was submitted on 05 Oct 2024
11 points (100.0% liked)

General Programming Discussion

7746 readers
18 users here now

A general programming discussion community.

Rules:

  1. Be civil.
  2. Please start discussions that spark conversation

Other communities

Systems

Functional Programming

Also related

founded 5 years ago
MODERATORS
 

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)

top 5 comments
sorted by: hot top controversial new old
[–] Limonene@lemmy.world 7 points 1 day ago (1 children)

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.

[–] velox_vulnus@lemmy.ml 5 points 1 day ago* (last edited 1 day 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@hexbear.net 3 points 1 day ago

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

[–] bufalo1973@lemmy.ml 1 points 1 day ago (1 children)

Don't you have to reserve the memory before showing it?

[–] huf@hexbear.net 4 points 1 day 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