mtproto icon indicating copy to clipboard operation
mtproto copied to clipboard

panic: runtime error: invalid memory address or nil pointer dereference

Open amir3code opened this issue 6 years ago • 6 comments

The code that I am writing is this:
What I am trying to do is to get a list of dialogs. But sometime panic error happens due to some network error.

package main

import (
	"github.com/cjongseok/mtproto"
	"context"
	"os"
	"fmt"
	"github.com/cjongseok/slog"
	"math/rand"
	"reflect"
)

func main() {
	// the acc we are using is: (telegram acc new three)
	caller := setUpLoggingNConnectNGetCaller()
	getDialogs(caller)                                                        // === line 16 ===
}

func getDialogs(caller *mtproto.RPCaller) *mtproto.PredMessagesDialogs {
	emptyPeer := &mtproto.TypeInputPeer{Value: &mtproto.TypeInputPeer_InputPeerEmpty{InputPeerEmpty: &mtproto.PredInputPeerEmpty{}}}
	var response *mtproto.TypeMessagesDialogs
	r, err := caller.MessagesGetDialogs(context.Background(), &mtproto.ReqMessagesGetDialogs{       //  === line 22 ===
		OffsetDate: 0, OffsetId: 0, OffsetPeer: emptyPeer,
	})
	if err != nil {
		fmt.Println("Can not get dialogs due to error:", err)
	}
	response = r

	dialogs := response.GetMessagesDialogs().GetDialogs()
	for _, item := range dialogs {
		fmt.Println(reflect.TypeOf(item.GetValue()))
		fmt.Println()
	}

	return response.GetMessagesDialogs()
}

func setUpLoggingNConnectNGetCaller() *mtproto.RPCaller {
	// set up logging
	logf, err := os.OpenFile("ss.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		fmt.Printf("error opening file: %v", err)
	}
	defer logf.Close()
	slog.SetLogOutput(logf)

	appVersion := "0.1"
	deviceModel := "SHIT"
	systemVersion := "0.2"
	language := "en"
	config, _ := mtproto.NewConfiguration(appVersion, deviceModel, systemVersion, language, 0, 0, "credentials.json")
	manager, _ := mtproto.NewManager(config)

	// Sign-in by key
	mconn, _ := manager.LoadAuthentication()
	caller := mtproto.RPCaller{RPC: mconn}
	return &caller
}

The error that happens is this:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7a61be]

goroutine 1 [running]:
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).LogPrefix(0x0, 0xc49d80, 0x0)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:363 +0x2e
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog.logprefix(0xc49d80, 0x0, 0x0, 0x12bc180)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog/slog.go:128 +0x29a
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog.Logln(0xc49d80, 0x0, 0xc420093860, 0x2, 0x2)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/slog/slog.go:165 +0x6d
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).Session(0x0, 0x1)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:151 +0xdc
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).InvokeNonBlocked(0x0, 0xd09ac0, 0xc420250580, 0xc420093d70)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:130 +0x90
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.(*Conn).InvokeBlocked(0x0, 0xd09ac0, 0xc420250580, 0x7f1b32e68d90, 0x0, 0x2, 0xdf8475800)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/conn.go:114 +0x5d
kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto.RPCaller.MessagesGetDialogs(0xd04060, 0x0, 0xd25760, 0xc4200d4050, 0xc420250580, 0xc88ace, 0x2, 0xdf8475800)
        /home/kasra/go/src/kasra/doingstuff_on_tg/vendor/github.com/cjongseok/mtproto/procs.tl.go:424 +0x57
main.getDialogs(0xc4202482f0, 0xc4200b8058)
        /home/kasra/go/src/kasra/doingstuff_on_tg/_accounts_/main.go:22 +0x127
main.main()
        /home/kasra/go/src/kasra/doingstuff_on_tg/_accounts_/main.go:16 +0x27
exit status 2

How can I handle this kind of error? (I have put comment after line 22 and 16 of my code to make it clear) As you can see I have received the error in err variable and checked it but I still get this panic.
Not to mention that I dont ALWAYS get this panic, It just happens sometimes due to network errors, How can I handle this one?

amir3code avatar Dec 30 '18 14:12 amir3code

@amir3code Thanks for your interest in this repository. It seems sometimes manager.LoadAuthentication() returns nil conn. Can you check it with

mconn, err := manager.LoadAuthentication()
if err != nil {
  fmt.Println(err)
}

instead of

mconn, _ := manager.LoadAuthentication()

For more evidences please share the log file ss.log after removing your credentials.

cjongseok avatar Dec 31 '18 02:12 cjongseok

For your information, if you want to fetch the list of all the channels and chat groups, I recommend to use MessagesGetAllChats() instead of MessagesGetDialogs(). Please check this simple shell command for the usage.

cjongseok avatar Dec 31 '18 02:12 cjongseok

I now have a ss.log file but it is crowded and over 1 megabyte! I will try to incorporate your change and post the log file in the next two days. BTW, one question. Is there any way to distinguish between a Super Group and a Channel? because they are both returned with the type Channel.

amir3code avatar Jan 01 '19 18:01 amir3code

Actually I have no idea for the problem. Although I checked responses from not only MessagesGetAllChats() but ChannelsGetFullChannel(), I couldn't get any difference between channel and group. So in my case I'm doing that manually, since I'm joined a couple of groups.

cjongseok avatar Jan 02 '19 05:01 cjongseok

Yeah yeah they are both the same unfortunately.
I have another question, How should I tell that for example MessagesGetAllChats method wants nothing in its arguments, how can I know that?
For example I have written the same as the simple shell file you told me:

func getDialogsAllTest(caller *mtproto.RPCaller) *mtproto.TypeMessagesDialogs {
	r, _ := caller.MessagesGetAllChats(context.Background(), &mtproto.ReqMessagesGetAllChats{})
	return r
}

The struct ReqMessagesGetAllChats should have nothing as argument for creation, right? but I see that It accepts one argument (assuming that XXX* are not necessary) ...

func getDialogsAllTest(caller *mtproto.RPCaller) *mtproto.TypeMessagesDialogs {
	r, _ := caller.MessagesGetAllChats(context.Background(), &mtproto.ReqMessagesGetAllChats{
		ExceptIds:            nil,
		XXX_NoUnkeyedLiteral: struct{}{},
		XXX_unrecognized:     nil,
		XXX_sizecache:        0,
	})
	return r
}

And that is ExceptIds. How should I tell that I do not have to fill this parameter. Is it all try and error or there is a documentation? How did you figured these out? Thanks for your time.

amir3code avatar Jan 02 '19 12:01 amir3code

Right it is all try and error. You can find some old methods in Telegram API document, but its version is too old (document: 23, cjongseok/mtproto: 71, latest: 91). Another documentation source is tdlib document. It is quite recent, but you know there is a interface gap between tdlib and tl-schema.

cjongseok avatar Jan 03 '19 10:01 cjongseok