## Attacking a Weird Java Error: java.lang.ClassFormatError: Invalid pc in line number table

While working on the Oracle Application Framework, my Application module’s class file was behaving in a strange manner. When it was deployed on Apache and run, it was throwing the following Error:


oracle.jbo.JboException: JBO-29000: Unexpected exception caught: java.lang.ClassFormatError, msg=oracle/apps/fnd/framework/test/updateAMImpl (Invalid pc in line number table)
at oracle.jbo.common.ampool.ApplicationPoolImpl.doCheckout(ApplicationPoolImpl.java:1619)
at oracle.jbo.common.ampool.ApplicationPoolImpl.useApplicationModule(ApplicationPoolImpl.java:2366)



I Googled on this error a lot, but most of the suggested solutions spoke about compiling the class with a different JDK or a different Java version and deploying it again. I tried to do that, but the error persisted.

## Decompiling using javap

I thought of decompiling the deployed class using the javap utility – if it would fail to decompile, that would surely indicate a problem with the class itself. However, javap decompiled it correctly, and correctly displayed public methods of the class.

I glanced through the help of javap (using -help), trying to figure out how to get a peek at the private methods too. While doing that, I noticed an interesting option: -verbose. This disassembles the code, and also prints the stack and line number table. Intrigued, I tried to run:

D:\JDeveloper\jdevhome\jdev\myclasses>javap -verbose oracle.apps.fnd.framework.test.UploadAMImpl > detailedclassUploadAMImpl


and it displayed the following (for the sake of brevity, I’ve pasted only relevant sections):


170: invokestatic #92; //Method oracle/apps/fnd/framework/OAException.wrapperException:(Ljava/lang/Exception;)Loracle/apps/fnd/framework/OAException;
173: athrow
174: astore 11
176: jsr 182
181: athrow
182: astore 12
186: invokestatic #88; //Method java/lang/String.valueOf:(I)Ljava/lang/String;
189: astore 8
193: areturn
Exception table:
from    to    target    type
77   148   154   Class java/sql/SQLException   156   163   166    Class java/lang/Exception   77    174    174    any
LineNumberTable:
line 150: 0
line 151: 8
line 152: 14
line 153: 39
line 154: 58
line 155: 70
line 156: 73
line 158: 77
line 159: 86
line 160: 95
line 161: 104
line 162: 112
line 163: 122
line 164: 141
line 165: 154
line 167: 156
line 168: 166
line 169: 168
line 170: 174
line 171: 184
line 172: 191
line 174: 193
line 173: 194



Looking at the line number table and disassembled code, I didn’t get anything conclusive. Then I just tried the same stuff on another class which was not having the same problem:


D:\JDeveloper\jdevhome\jdev\myclasses>javap -verbose oracle.apps.fnd.framework.test.webui.testEmpCO
> CODetailed


which gave me following output (again pasting relevant sections for sake of brevity)


433: invokeinterface #28, 2; //InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
438: checkcast #29; //class String
441: astore 10
443: aconst_null
446: if_acmpeq 461
458: invokespecial #79; //Method _triggerProcess:(Loracle/apps/fnd/framework/webui/OAPageContext;Loracle/apps/fnd/framework/OAApplicationModule;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
461: return
Exception table:
from    to    target    type
223    324    327    Class oracle/apps/fnd/framework/OAExceptionLineNumberTable:
line 138: 0
line 140: 8
line 141: 14
line 142: 26
line 144: 34
line 145: 42
line 147: 52
line 148: 58
line 149: 73
line 150: 88
line 152: 107
line 153: 122
line 155: 133
line 156: 152
line 157: 171
line 158: 187
line 159: 206
line 161: 212
line 167: 223
line 168: 245
line 170: 254
line 171: 259
line 173: 274
line 175: 286
line 177: 300
line 178: 305
line 180: 316
line 185: 327
line 187: 329
line 188: 337
line 190: 346
line 191: 362
line 192: 375
line 193: 383
line 194: 391
line 196: 397
line 200: 411
line 201: 427
line 202: 443
line 203: 449
line 213: 461



I tried to compare the verbose output of both. Though I couldn’t make much out of it, I noticed one thing: for correct class (testEmpCO), the last line number in line number table (line 213: 461) against the last assembly instruction was same as the last line number of the disassembled code.(461: return)

However, for the class which had the error (UploadAMImpl), the last line in the line number table was 194 (line 173: 194). However the last line number for disassembled code was 193 (193: areturn). I became curious and checked the last assembly instruction which was starting at line 173 (pasted again below):


170: invokestatic #92; //Method oracle/apps/fnd/framework/OAException.wrapperException:(Ljava/lang/Exception;)Loracle/apps/fnd/framework/OAException;
173: athrow



Though I couldn’t decipher it completely, I could make out from instructions that it was something related to OAWrapperException, which was present in my code.

I decided to replace the same with OAException which is the normally followed practice instead of OAWrapperException, which I had copied from Fwk developer’s guide. After doing the change, I ran again


AMDetailed.server



and the following was the output:


195: invokespecial #32; //Method oracle/apps/fnd/framework/OAException."":(Ljava/lang/String;B)V
198: athrow
199: return
Exception table:
from    to    target    type
13    178    181    Class java/lang/ExceptionLineNumberTable:
line 106: 0
line 107: 8
line 109: 13
line 110: 20
line 112: 27
line 113: 43
line 114: 59
line 115: 74
line 116: 85
line 117: 104
line 118: 114
line 119: 130
line 120: 146
line 121: 162
line 123: 181
line 124: 182
line 125: 186
line 127: 199



Now, last line number in line number table 199 (line 127: 199) was matching with last line number of disassembled code ( 199: return). I hoped by now that this should work and after deploying, it really worked !!!!

I don’t know what was causing OAWrapperException to cause this issue , but I thought I would share this technique as this is generic error and it can be encountered by any java programmer. This is rare error and that is why it is difficult to address, as not lot of practical help is available on this and programmers can learn to unleash the power of javap and its various options.

I hope the technique I’ve described above will be handy for programmers who come across this kind of error.

Our guest writer, Vishal Chougule, is an avid Java developer and a technology lover. His interests range from computer security to design patterns.

## A Quick Tutorial to Set Up an NFS Server on Windows

Update (Nov 9, 2011): As noted in the comments below, Windows Services for UNIX Version (SFU) is no longer supported on Windows 7 and 2008. For these versions, try installing Cygwin with the optional nfs-server component. If you’re using Windows 2008, you can use the Server for NFS that comes built-in instead – in this case, most of the steps below should apply.

A few days ago, I needed to share a large folder present on a Windows server to access it from my local Ubuntu workstation. I initially used Samba, but my build script refused to recognize paths present in that share.

The solution was to use an NFS share – but this required a special setup on Windows. Even after a lot of searching on Google, I couldn’t easily find a guide that talked about how to get started with an NFS server on Windows quickly. Most articles I came across were only detailing information on NFS security, or some obscure command line options for tweaking NFS options – which shouldn’t be required when all you want is a simple share within your local, protected network.

So, here’s what to need to do if you need an NFS server enabled on Windows quickly, and mount it on your Linux box:

2) Run setup.exe from the extracted directory.

3) Follow the prompts, until you reach the following screen:

Choose custom installation – since we’d like to only install the NFS server for sharing folders.

4) Choose the following three components to install:
(i) NFS -> Server for NFS
(ii) Authentication tools for NFS -> User Name Mapping
(iii) Authentication tools for NFS -> Server for NFS Authentication

Here’s a pictorial representation of the components you’ll need:

5) On the next screen, choose to change the behavior to case-sensitive, to provide full compatibility with UNIX programs

6) On the User Name Mapping screen, choose “Local User Name Mapping Server” and “Password and group files”:

7) Now, copy your passwd and group files from your UNIX/Linux distribution onto your Windows machine. For Ubuntu, these are located at /etc/passwd and /etc/group. Provide the paths to these files in the next screen:

8) Continue with the installation prompts until you finish.

9) Windows Services for UNIX should now be installed:

10) Open the Services for UNIX Administration shortcut, and click on User Name Mapping:

11) Click on “Show User Maps” and then click on the buttons for Listing Windows Users and Linux Users:

12) Choose “Administrator” (or the appropriate account you want to map the UNIX user to) in the Windows list, and your username in the Linux list. (In Ubuntu, UIDs for user accounts usually start from 1000)

13) Click “Add” to create a map. If you get the following warning, click “OK” to ignore it.

14) Click Apply at the top right corner.

15) Now, you’re ready to share folders! Just right click any folder you need to share, and share it from the NFS tab. You can click the Permissions button for more options, like allowing write access, which is disallowed by default.

16) Next, mount the share on your UNIX/Linux machine. I used the following command on Ubuntu:

$sudo mount <windows-server-ip-address>:/<windows_share_name> <path_to_local_mount_point> For example: $ sudo mount 192.168.1.3:/SharedFolder ~/windows_share

If this guide helped you, please let us know in the comments below!

## Automatic Login For SSH/SFTP on Ubuntu

There are just three simple steps needed to automate your SSH/SFTP logins to remote Unix/Unix-like servers from your Ubuntu/Linux distribution, or an emulator on Windows like Cygwin.

1) Run ssh-keygen

abdullah@desktop:~$ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/abdullah/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/abdullah/.ssh/id_rsa. Your public key has been saved in /home/abdullah/.ssh/id_rsa.pub. The key fingerprint is: 06:23:fc:34:0f:12:40:b2:5e:7c:41:eb:4f:a2:ab:24 abdullah@desktop The key's randomart image is: 2) Run ssh-copy-id <username>@<server-name> abdullah@desktop:~$ ssh-copy-id login@myserver.com
Now try logging into the machine, with "ssh 'login@myserver.com'", and check in:

~/.ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.


abdullah@desktop:~\$ ssh 'login@myserver.com'
Welcome to MyServer.com!
Last login: Sun Sep 25 23:22:21 2011 from 209.85.175.105


That’s all!

If you want a quick shortcut in the GUI, you could add a Custom Application Launcher to the panel with the ssh login command, as shown below:

Clicking the panel icon will directly open the terminal at the server with you logged in.

Note that this will also automate the login for SFTP, so you won’t need to type in your passwords there anymore too!

## How to Delete a Directory in Linux

To delete or remove a directory in Linux, use the “-r” flag to the “rm” command. “r” stands for recursive.

rm -r <directory_name>

On some Linux systems, you might be prompted before each file is deleted. This means that the rm command has been aliased to “rm -i”, which turns on interactive mode. To run the original rm command and avoid the prompts, use “\rm”:

\rm -r <directory_name>

In the bash shell, just as the backslash is used to escape special characters, it is also used to escape aliases.

### Caution!

Be careful to double check the directory name you provide, and be extra careful when using wildcards. There have been many stories of grief because of users ending up deleting important files and folders recursively.