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

Parsing a Session Description on Android causes a NullPointerException. #267

Open
jussme opened this issue Feb 1, 2023 · 7 comments
Open

Comments

@jussme
Copy link

jussme commented Feb 1, 2023

Artifact version: 3.0-61-g76e8a19

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.util.Hashtable.get(java.lang.Object)' on a null object reference
    at gov.nist.core.LexerCore.match(LexerCore.java:226)
    at gov.nist.javax.sdp.parser.OriginFieldParser.originField(OriginFieldParser.java:52)
    at gov.nist.javax.sdp.parser.OriginFieldParser.parse(OriginFieldParser.java:108)
    at gov.nist.javax.sdp.parser.SDPAnnounceParser.parse(SDPAnnounceParser.java:113)
    at org.opentelecoms.javax.sdp.NistSdpFactory.createSessionDescription(NistSdpFactory.java:62)
    at pl.mk.touchpad.server.ext.SdpUtils.parseSDP(SdpUtils.java:76)
    at pl.mk.touchpad.server.ext.RemoteConnector.pair(RemoteConnector.java:62)
    at pl.mk.touchpad.connection.net.punching.RemoteActiveConnector.connect(RemoteActiveConnector.java:66)
    at pl.mk.touchpad.connection.ControllingActivity.lambda$onCreate$0$pl-mk-touchpad-connection-ControllingActivity(ControllingActivity.java:53)
    at pl.mk.touchpad.connection.ControllingActivity$$ExternalSyntheticLambda2.run(Unknown Source:4)
    at java.lang.Thread.run(Thread.java:784)
java.text.ParseException: o=ice4j.org 0 0 IN IP4 123.12.123.123
    at gov.nist.javax.sdp.parser.OriginFieldParser.originField(OriginFieldParser.java:103)
    at gov.nist.javax.sdp.parser.OriginFieldParser.parse(OriginFieldParser.java:108)
    at gov.nist.javax.sdp.parser.SDPAnnounceParser.parse(SDPAnnounceParser.java:113)
    at org.opentelecoms.javax.sdp.NistSdpFactory.createSessionDescription(NistSdpFactory.java:62)
    at pl.mk.touchpad.server.ext.SdpUtils.parseSDP(SdpUtils.java:76)
    at pl.mk.touchpad.server.ext.RemoteConnector.pair(RemoteConnector.java:62)
    at pl.mk.touchpad.connection.net.punching.RemoteActiveConnector.connect(RemoteActiveConnector.java:66)
    at pl.mk.touchpad.connection.ControllingActivity.lambda$onCreate$0$pl-mk-touchpad-connection-ControllingActivity(ControllingActivity.java:53)
    at pl.mk.touchpad.connection.ControllingActivity$$ExternalSyntheticLambda2.run(Unknown Source:4)
    at java.lang.Thread.run(Thread.java:784)
javax.sdp.SdpParseException: o=ice4j.org 0 0 IN IP4 123.12.123.123
    at org.opentelecoms.javax.sdp.NistSdpFactory.createSessionDescription(NistSdpFactory.java:66)
    at pl.mk.touchpad.server.ext.SdpUtils.parseSDP(SdpUtils.java:76)
    at pl.mk.touchpad.server.ext.RemoteConnector.pair(RemoteConnector.java:62)
    at pl.mk.touchpad.connection.net.punching.RemoteActiveConnector.connect(RemoteActiveConnector.java:66)
    at pl.mk.touchpad.connection.ControllingActivity.lambda$onCreate$0$pl-mk-touchpad-connection-ControllingActivity(ControllingActivity.java:53)
    at pl.mk.touchpad.connection.ControllingActivity$$ExternalSyntheticLambda2.run(Unknown Source:4)
    at java.lang.Thread.run(Thread.java:784)

It seems to be thrown when calling .get() on LexerCore.currentLexer.

I've added the line currentLexer = new ConcurrentHashMap() to the constructor missing it, with Recaf. Android Studio and other decompilers confirm that it's being instantiated in both constructors (it's moved to the field declaration to be precise) but nothing changed.

@Neerajsh8851
Copy link

Have you found any solution?

@jussme
Copy link
Author

jussme commented Jun 11, 2023

@Neerajsh8851 Sadly i have not, did you?

@jussme
Copy link
Author

jussme commented Jun 14, 2023

I added some printlns to LexerCore and they don't happen on Android. Also, when inspecting the fields of LexerCore, on Android with reflection, the Map fields are of type Hashtable:

protected java.util.Hashtable gov.nist.core.LexerCore.currentLexer
protected java.lang.String gov.nist.core.LexerCore.currentLexerName
protected gov.nist.core.Token gov.nist.core.LexerCore.currentMatch
public static final int gov.nist.core.LexerCore.ALPHA
static final char gov.nist.core.LexerCore.ALPHADIGIT_VALID_CHARS
static final char gov.nist.core.LexerCore.ALPHA_VALID_CHARS
public static final int gov.nist.core.LexerCore.AND
public static final int gov.nist.core.LexerCore.AT
public static final int gov.nist.core.LexerCore.BACKSLASH
public static final int gov.nist.core.LexerCore.BACK_QUOTE
public static final int gov.nist.core.LexerCore.BAR
public static final int gov.nist.core.LexerCore.COLON
public static final int gov.nist.core.LexerCore.DIGIT
static final char gov.nist.core.LexerCore.DIGIT_VALID_CHARS
public static final int gov.nist.core.LexerCore.DOLLAR
public static final int gov.nist.core.LexerCore.DOT
public static final int gov.nist.core.LexerCore.DOUBLEQUOTE
public static final int gov.nist.core.LexerCore.END
public static final int gov.nist.core.LexerCore.EQUALS
public static final int gov.nist.core.LexerCore.EXCLAMATION
public static final int gov.nist.core.LexerCore.GREATER_THAN
public static final int gov.nist.core.LexerCore.HAT
public static final int gov.nist.core.LexerCore.HT
public static final int gov.nist.core.LexerCore.ID
public static final int gov.nist.core.LexerCore.LESS_THAN
public static final int gov.nist.core.LexerCore.LPAREN
public static final int gov.nist.core.LexerCore.L_CURLY
public static final int gov.nist.core.LexerCore.L_SQUARE_BRACKET
public static final int gov.nist.core.LexerCore.MINUS
public static final int gov.nist.core.LexerCore.NULL
public static final int gov.nist.core.LexerCore.PERCENT
public static final int gov.nist.core.LexerCore.PLUS
public static final int gov.nist.core.LexerCore.POUND
public static final int gov.nist.core.LexerCore.QUESTION
public static final int gov.nist.core.LexerCore.QUOTE
public static final int gov.nist.core.LexerCore.RPAREN
public static final int gov.nist.core.LexerCore.R_CURLY
public static final int gov.nist.core.LexerCore.R_SQUARE_BRACKET
public static final int gov.nist.core.LexerCore.SAFE
public static final int gov.nist.core.LexerCore.SEMICOLON
public static final int gov.nist.core.LexerCore.SLASH
public static final int gov.nist.core.LexerCore.SP
public static final int gov.nist.core.LexerCore.STAR
public static final int gov.nist.core.LexerCore.START
public static final int gov.nist.core.LexerCore.TILDE
public static final int gov.nist.core.LexerCore.UNDERSCORE
public static final int gov.nist.core.LexerCore.WHITESPACE
protected static final java.util.Hashtable gov.nist.core.LexerCore.globalSymbolTable
protected static final java.util.Hashtable gov.nist.core.LexerCore.lexerTables

And on desktop, notice the dummyField field i added:

public static final int gov.nist.core.LexerCore.START
public static final int gov.nist.core.LexerCore.END
public static final int gov.nist.core.LexerCore.ID_NO_WHITESPACE
public static final int gov.nist.core.LexerCore.ID
public static final int gov.nist.core.LexerCore.SAFE
public static final int gov.nist.core.LexerCore.WHITESPACE
public static final int gov.nist.core.LexerCore.DIGIT
public static final int gov.nist.core.LexerCore.ALPHA
public static final int gov.nist.core.LexerCore.BACKSLASH
public static final int gov.nist.core.LexerCore.QUOTE
public static final int gov.nist.core.LexerCore.AT
public static final int gov.nist.core.LexerCore.SP
public static final int gov.nist.core.LexerCore.HT
public static final int gov.nist.core.LexerCore.COLON
public static final int gov.nist.core.LexerCore.STAR
public static final int gov.nist.core.LexerCore.DOLLAR
public static final int gov.nist.core.LexerCore.PLUS
public static final int gov.nist.core.LexerCore.POUND
public static final int gov.nist.core.LexerCore.MINUS
public static final int gov.nist.core.LexerCore.DOUBLEQUOTE
public static final int gov.nist.core.LexerCore.TILDE
public static final int gov.nist.core.LexerCore.BACK_QUOTE
public static final int gov.nist.core.LexerCore.NULL
public static final int gov.nist.core.LexerCore.EQUALS
public static final int gov.nist.core.LexerCore.SEMICOLON
public static final int gov.nist.core.LexerCore.SLASH
public static final int gov.nist.core.LexerCore.L_SQUARE_BRACKET
public static final int gov.nist.core.LexerCore.R_SQUARE_BRACKET
public static final int gov.nist.core.LexerCore.R_CURLY
public static final int gov.nist.core.LexerCore.L_CURLY
public static final int gov.nist.core.LexerCore.HAT
public static final int gov.nist.core.LexerCore.BAR
public static final int gov.nist.core.LexerCore.DOT
public static final int gov.nist.core.LexerCore.EXCLAMATION
public static final int gov.nist.core.LexerCore.LPAREN
public static final int gov.nist.core.LexerCore.RPAREN
public static final int gov.nist.core.LexerCore.GREATER_THAN
public static final int gov.nist.core.LexerCore.LESS_THAN
public static final int gov.nist.core.LexerCore.PERCENT
public static final int gov.nist.core.LexerCore.QUESTION
public static final int gov.nist.core.LexerCore.AND
public static final int gov.nist.core.LexerCore.UNDERSCORE
protected static final java.util.concurrent.ConcurrentHashMap gov.nist.core.LexerCore.globalSymbolTable
protected static final java.util.concurrent.ConcurrentHashMap gov.nist.core.LexerCore.lexerTables
protected java.util.Map gov.nist.core.LexerCore.currentLexer
protected java.lang.String gov.nist.core.LexerCore.dummyField
protected java.lang.String gov.nist.core.LexerCore.currentLexerName
protected gov.nist.core.Token gov.nist.core.LexerCore.currentMatch
static final char gov.nist.core.LexerCore.ALPHA_VALID_CHARS
static final char gov.nist.core.LexerCore.DIGIT_VALID_CHARS
static final char gov.nist.core.LexerCore.ALPHADIGIT_VALID_CHARS

This is from the same artifact on Android and Desktop. Also, the lines executed seen in Android debugger don't match the source file. Changes made to LexerCore don't seem to effect the artifact. What is going on here? I don't see reflection being used in regards to LexerCore. Why is LexerCore on runtime different from the source code?

@jussme
Copy link
Author

jussme commented Jun 15, 2023

Also, a println added to the class static block is not executed.

@Neerajsh8851
Copy link

@Neerajsh8851 Sadly i have not, did you?

I am creating my own solution in kotlin. I found pj project but that was in c.

@davidliu
Copy link

@jussme Did a little digging, and the issue is because LexerCore appears to conflict with a hidden embedded framework class. Looking at the LexerCore class with a debugger, you can find a dexCache field which I believe indicates the location the class was loaded from. Other app classes have a path consistent with coming from the apk's dex files, but LexerCore gives me a path /system/framework/voip-common.jar. It looks like they have an internal copy of the NIST classes. Not sure how to workaround this issue; will need an android specific build like https://mvnrepository.com/artifact/javax.sip/android-jain-sip-ri which changes the package names so this conflict doesn't happen.

@davidliu
Copy link

Not sure if it will work for Ice4J as well, but you can try shadowing the jars to avoid the class name conflict. This can be done fairly simply with a shadow plugin like https://imperceptiblethoughts.com/shadow/.

I'm using this on java-sdp-nist-bridge, which includes the jain-sip library. For simplicity, I just have a separate gradle module that has all the dependencies I want to shadow, and then I use the auto-relocation feature to prefix everything, and depend on the shadow module from my app module.

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

3 participants