6

In golang, can I print the value of a memory address from a given string?

For example, if run the following code:

a := "A String"
fmt.Println(&a)

It prints 0x1040c108.

How could I take a string such as 0x1040c108 and print the value of that string stored in the memory? Something like fmt.Println(*0x1040c108)

Is this possible?

4
  • My question is very similar to stackoverflow.com/questions/27539388 Commented May 3, 2017 at 17:39
  • 3
    You really don't want to do this.... Commented May 3, 2017 at 18:17
  • In what possible scenario would you ever want to do this? Just reading the question sets off all the alarms in my head. Commented May 3, 2017 at 19:52
  • 2
    @Adrian I didn't really need to know the answer to this for any projects of mine. It was just to satisfy my curiosity. Commented May 4, 2017 at 7:12

3 Answers 3

13

This can be done, but it is a really really REALLY bad idea. Anytime you are importing the unsafe package, you are either doing something wrong, or something really hardcore. I'm hesitant to even answer this, but here goes.

https://play.golang.org/p/unkb-s8IzAo

package main

import (
    "fmt"
    "strconv"
    "unsafe"
)

func main() {
    // original example manually examined the printed address and used the value
    // updated to preserve forward compatibility due to runtime changes shifting the address over time

    hi := "HI"

    // getting address as string dynamically to preserve compatibility
    address := fmt.Sprint(&hi)

    fmt.Printf("Address of var hi: %s\n", address)

    // convert to uintptr
    var adr uint64
    adr, err := strconv.ParseUint(address, 0, 64)
    if err != nil {
        panic(err)
    }
    var ptr uintptr = uintptr(adr)

    fmt.Printf("String at address: %s\n", address)
    fmt.Printf("Value: %s\n", ptrToString(ptr))
}

func ptrToString(ptr uintptr) string {
    p := unsafe.Pointer(ptr)
    return *(*string)(p)
}

And yes, this was pretty much taken almost line for line from the unsafe godoc. https://godoc.org/unsafe

Also note that if/when your memory reference is NOT a go string, everything will come crashing down catastrophically. And that go vet is configured to send you an angry message for doing this, reinforcing that this is indeed a bad idea.

UPDATE: Updated example to run on playground as of go 1.15.1, which either the playground or go itself has changed the way the memory is addressed. Or the more likely case that changes in core libs/runtime will shift the address across versions. It now dynamically obtains the address vs a manually hardcoded value.

Sign up to request clarification or add additional context in comments.

10 Comments

By the way, I'm really surprised that it doesn't require you to know the length and loop over each individual character.
A string value includes the length.
Can you elaborate on "everything will come crashing down catastrophically" please. Seems like I've asked a critically dangerous question.
Hm, I opened your example on the Go playground and I simply removed the line fmt.Println("Hello, Playground") which caused the output to only print the memory address of hi. Very interesting.
@Acidic Oops, yeah, I always manage to forget to remove that. The reason it breaks it is because a string is created in memory when "Hello, Playground" is passed to fmt, so the memory address of the string created with hi := "HI" is different. So apparently go doesn't panic if it's not a string. Interesting.
|
2
package main

import "C"

import (
    "log"
    "strconv"
    "unsafe"
)

func main() {

    // parse the string into an integer value
    addr, _ := strconv.ParseInt("0x1040c108", 0, 64)

    // cast the integer to a c string pointer
    ptr := (*C.char)(unsafe.Pointer(uintptr(addr)))

    // convert to a go string (this will segfault)
    str := C.GoString(ptr)

    // print it
    log.Println(str)
}

3 Comments

@RayfenWindspear assuming the string in memory is a Go string.
The OP wants to dereference arbitrary raw pointer values. Many assumptions are going to be made... here be dragons...
Heh, fair enough
0

Yes!! you can store the address in a pointer variable and print its value by derefrencing it

i := "something"
ptr := &i
fmt.Println(*ptr)

For accessing the memory using a hard coded address such as 0x1040c108, it is necessary for your program to have access to that memory address otherwise, you will get an error saying invalid indirection of a pointer or segmentation fault.

5 Comments

I'm not talking about pointing to a variable's memory address that was made in the program... I mean using a string (such as "0x1040c108") and checking the value of that memory address in the computer's memory.
@Acidic: what does it mean to "check it"? Do you want to assume the type to read and just hope you don't segfault?
It's really confusing, but yeah I guess that could be an issue... not knowing the memory address' value's type. But if you ignore the type (assuming somehow you know what it is), is it possible?
The edit you just made is false. ptr, _ := strconv.ParseInt(addr, 0, 64) does not create a pointer, it creates an int. fmt.Println(*ptr) therefore is an invalid indirect because it isn't a pointer. You can only use * operator on variables you've previously taken the pointer of &.
ty for noticing

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.