Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface Conversion Error #20

Closed
piano-man opened this issue Apr 5, 2020 · 9 comments
Closed

Interface Conversion Error #20

piano-man opened this issue Apr 5, 2020 · 9 comments

Comments

@piano-man
Copy link
Contributor

The error I'm running into is this :-

panic: interface conversion: quictracker.Frame is quictracker.MaxDataFrame, not *quictracker.MaxDataFrame

To provide context,
I have a function which receives a pointer to a frame i.e. frame *Frame. I then determine the type of the frame using (*frame).FrameType() which evaluates to MaxDataType. Following this, when I try to extract the MaximumData value using (*frame).(*MaxDataFrame).MaximumData, I run into the error above.

I'm unable to figure out the correct way of extracting MaximumData value from the frame.

@mpiraux
Copy link
Member

mpiraux commented Apr 6, 2020

I always tried to implement and use Frame as a pointer type, so that you can either always do (*TheFrameType). Looks like I failed somewhere for MaxDataFrame. I will look at where this is coming from.

@mpiraux
Copy link
Member

mpiraux commented Apr 6, 2020

So the code in this repository seems to be type coherent. It may be coming from your code then ?
I guess you instantiate a Frame with the value of MaxDataFrame struct and not a pointer to that value. The cast you mention is correct, but it only works when all your code agree on using frames as pointers. I don't use pointers of Frame, because all frames implementing the interface are already pointers. Go kind of restrain you from doing so by forcing you to type (*frame) before the cast.
So, I can advice you to look at all frame structure initialisation and make sure you are passing a pointer to the struct to the other Frame handling parts the code.

@piano-man
Copy link
Contributor Author

But if there was an issue with the initialization, wouldn't (*frame).FrameType() not work either ?
Because I'm only going to (*frame).(*MaxDataFrame).MaximumData if (*frame).FrameType() == MaxDataType

@piano-man
Copy link
Contributor Author

I essentially have a function that receives a pointer to a frame (frame *Frame) and and then a switch case depending on the type of the frame. It works for all other frames, just throws this error for MaxStreamDataType, MaxDataType and MaxStreamsType.

Also, I'm not really creating or initialising a frame. I pass a pointer to a packet (packet *Packet) to a function from EncodeAndEncrypt. I then extract the frames from the packet using -

frames := (*packet).(Framer).GetFrames()
for i, _ := range frames {
			&((*packet).(Framer).GetFrames()[i]) // this is the pointer to the frame (frame *Frame) mentioned originally in the issue which I pass to the function 
	}

@mpiraux
Copy link
Member

mpiraux commented Apr 6, 2020

(*frame).FrameType() works because Go can cope with either *MaxDataFrame and MaxDataFrame for method invocation. But a direct cast is stricter. I am no Go expert so there might be plenty of better docs on that subject.
By greping your code I found:

./scenarii/flow_control.go:
conn.FrameQueue.Submit(qt.QueuedFrame{qt.MaxDataFrame{uint64(conn.TLSTPHandler.MaxData)}, qt.EncryptionLevel1RTT})

I have fixed this in aa881ba.

@piano-man
Copy link
Contributor Author

piano-man commented Apr 6, 2020

I updated the code, but still run into the same problem.

I experimented a little more and found something really surprising.
For the scenario where I was getting the above error, I changed (*frame).(*MaxDataFrame).MaximumData to (*frame).(MaxDataFrame).MaximumData and I was able to access the value(not change it but just read it). However, for a different scenario, I now get the following error -
panic: interface conversion: quictracker.Frame is *quictracker.MaxDataFrame, not quictracker.MaxDataFrame
which is a total opposite of the earlier error.

I figured maybe passing packets and frames using pointers is leading to the unexpected behaviour, so I removed all reference passing from my code and still got the same behaviour.

Considering that I have done no initialization and am just trying to access these values from packets when they reach EncodeAndEncrypt function, I can't understand what's happening at all.(Infact, just to be extra sure, I cloned a fresh copy of the repo and added only a couple of lines in the connection.go file which extract the frames from the packet to make sure something else in my code wasn't leading to this)
Also, the problem occurs with different types of frames as well.
And for a scenario, in the same packet, some types of frame require one type of cast while others require a different type.
(I'm sorry if this is taking up too much of your time)

@piano-man
Copy link
Contributor Author

Infact, this specific test case might help you see the error first hand.
First, I add these lines to the EncodeAndEncrypt function in connection.go

if packet.PNSpace() == PNSpaceAppData {
        framePacket, ok := (packet).(Framer)                                                                                                                                       
        if ok {                                                                                                                                                                  
           frames := framePacket.GetFrames()                                                                                                                                         
           for _, frame := range frames {                                                                                                                                             
                fmt.Println("Frame type", frame.FrameType())                                                                                                                               
                if frame.FrameType() == StreamType {                                                                                                                                        
                     fmt.Println("Processing Stream Frame")                                                                                                                                                  
                      fmt.Println(frame.(*StreamFrame).StreamId)                                                                                                                                                                                                                                                                                                           
                }                                                                                                                                                                          
             }
          }                                                                                                                                                                         
}

Now, I run the scenario_runner.go script for http3_get and the sever_flow_control scenario against the host quic.tech:8443.
While http3_get will work fine, the server_flow_control scenario will throw the error -
panic: interface conversion: quictracker.Frame is quictracker.StreamFrame, not *quictracker.StreamFrame.
If I change frame.(*StreamFrame).StreamId to frame.(StreamFrame).StreamId, server_flow_control works fine while http3_get will throw the error -
panic: interface conversion: quictracker.Frame is *quictracker.StreamFrame, not quictracker.StreamFrame.

@mpiraux
Copy link
Member

mpiraux commented Apr 8, 2020

Thank you for taking the time to dig this up. I rarely have to look into the packets that are sent and I have found some occurences of this type inconsistency recently when adding qlog. I found another one in server_flow_control. A fix is pushed that changes all Frame-implementing structs to use pointers. Now it fails to compile when using an existing frame struct as a value and not a pointer. I think this will end all the troubles listed here.

@piano-man
Copy link
Contributor Author

Great ! Works well now :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants