Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / September 2006

Tip: Looking for answers? Try searching our database.

Why is String immutable?

Thread view: 
dimitrik107@hotmail.com - 11 Sep 2006 14:42 GMT
Why String is immutable? Is there simple explanation I can't find it?
Fred Kleinschmidt - 11 Sep 2006 15:53 GMT
> Why String is immutable? Is there simple explanation I can't find it?

For the same reason Integer is immutable: that's how the author(s) decided
to do it.

You could also ask: Why isn't a StringBuffer immutable?
Signature

Fred L. Kleinschmidt
Boeing Associate Technical Fellow
Technical Architect, Software Reuse Project

Chris Smith - 11 Sep 2006 16:16 GMT
> Why String is immutable? Is there simple explanation I can't find it?

There are at least two reasons.

The first is a design principle.  Immutable classes for basic types like
String make designs much more comprehensible.  If you pass a String
around the application, you don't need to worry about who else has a
reference to it, who might modify it without your realizing the
possibility, and so forth.  Especially in a heavily multithreaded
environment like Java, that's the only way that it's safe to share a
String throughout the application.

The second reason has to do with the Java security model.  When a
security policy is installed, certain restrictions can be enforced on --
for example -- which files can be read, which hosts can be connected to
over the network, and so on.  The immutable String class ensures that
security-sensitive APIs only have to check the file name or host name
once, and can then rely on it to stay the same.  A mutable String class
would introduce a race condition where the application (in another
thread) could modify the file name after the security check, but before
the file is actually opened, and thus circumvent the security mechanism.

If you think about it, you'll notice that when seen from some
perspectives, the second is a specialization on the first reason.

Signature

Chris Smith

Matt Rose - 11 Sep 2006 17:45 GMT
> The second reason has to do with the Java security model.  When a
> security policy is installed, certain restrictions can be enforced on --
[quoted text clipped - 5 lines]
> thread) could modify the file name after the security check, but before
> the file is actually opened, and thus circumvent the security mechanism.

Hi, I wholeheartedly agree with your first point of it being the only
sane way to implement Strings from a design point of view, but I'm less
sure about relying on this for security. The underlying char[] is still
writable if you try a bit harder. I expect the method below could be
forbidden with the right security policy (ReflectPermission
seems to be granted by default on my system) but I suspect you could
still access the field directly if you craft your own byte code?

import java.lang.reflect.Field;

public class StringImmutabilityTest {

    public static void main(String[] args) throws Exception {
        String fileNameToServe = "/ftp/readme";
        char[] injection = "/etc/passwd".toCharArray();
        Field f = fileNameToServe.getClass().getDeclaredField("value");
        f.setAccessible(true);
        char[] val = (char[]) f.get(fileNameToServe);
        System.arraycopy(injection, 0, val, 0, injection.length);
        System.out.println(fileNameToServe);
    }
}

Of course, you're probably doomed the moment you allow untrusted code
into your VM anyway!

By the way, calling new String(String) on any untrusted Strings will
probably keep you a little safe from this.

Matt
Matt Rose - 11 Sep 2006 18:09 GMT
> > The second reason has to do with the Java security model.  When a
> > security policy is installed, certain restrictions can be enforced on --
[quoted text clipped - 36 lines]
>
> Matt

Hmm, I take it back about new String(String) helping. This contructor
only copies the char[] if original String had some wasted space, e.g.
it was the product of a subString().

You'd need to duplicate the char[] yourself and wrap that in a String
if you're worried about malicious people having references to your
Strings.

Matt
Chris Smith - 12 Sep 2006 03:19 GMT
> Hi, I wholeheartedly agree with your first point of it being the only
> sane way to implement Strings from a design point of view, but I'm less
[quoted text clipped - 3 lines]
>  seems to be granted by default on my system) but I suspect you could
> still access the field directly if you craft your own byte code?

Everything is granted by default.  The point is that if you install a
security manager, you can control this stuff.  There are some
permissions that can never be granted to security-sensitive code; but
you just don't grant those permissions.  One of those is
ReflectPermission("suppressAccessChecks"), which covers the call to
setAccessible.

> Of course, you're probably doomed the moment you allow untrusted code
> into your VM anyway!

Not at all.  That's what applets do, millions of times per day.  If you
were right, then someone could really cause havoc around the world.  
You're not right, though.

Signature

Chris Smith

Matt Rose - 12 Sep 2006 12:47 GMT
> > Hi, I wholeheartedly agree with your first point of it being the only
> > sane way to implement Strings from a design point of view, but I'm less
[quoted text clipped - 10 lines]
> ReflectPermission("suppressAccessChecks"), which covers the call to
> setAccessible.

Does this get checked by the GETFIELD opcode? I can't find any
indication that it does in the VM spec but I haven't tested it. I never
normally get involved with bytecode.

> > Of course, you're probably doomed the moment you allow untrusted code
> > into your VM anyway!
>
> Not at all.  That's what applets do, millions of times per day.  If you
> were right, then someone could really cause havoc around the world.
> You're not right, though.

Excellent point, well made. It's easy to forget java is used on the
client side, too.

Matt
Chris Smith - 12 Sep 2006 16:55 GMT
> Does this get checked by the GETFIELD opcode? I can't find any
> indication that it does in the VM spec but I haven't tested it. I never
> normally get involved with bytecode.

The getfield opcode is checked by the bytecode verifier when the class
is loaded.  If it tries to access a field to which it doesn't have
access permission, the verifier will throw a java.lang.VerifyError, and
the class will fail to load.

This has nothing to do with ReflectPermission("suppressAccessChecks");
it just is.  If you want to suppress access checks, you can't do it with
direct bytecode instructions to access the hidden methods and fields.  
Even if you were to call setAccessible, you still couldn't load bytecode
that tries to access a private field directly.  You would need to use
the Reflection API to do that.

As long as we're on the topic, it should be mentioned that the
discussion of private fields might be misleading.  From a security
standpoint, private is actually considerably less interesting than
package-access restrictions.  The Java compiler routinely generates
hidden package-access methods that allow access to private fields
(particularly when dealing with nested classes), so relying on private
access is not safe.  Building a secure API requires placing classes in a
sealed package, and then ensuring that all protected or public access
meets the security requirements.  Since the core API packages are
sealed, this is exactly what happens here.

Signature

Chris Smith

Babu Kalakrishnan - 12 Sep 2006 18:49 GMT
> As long as we're on the topic, it should be mentioned that the
> discussion of private fields might be misleading.  From a security
[quoted text clipped - 6 lines]
> meets the security requirements.  Since the core API packages are
> sealed, this is exactly what happens here.

One query in connection with that last statement. Remember seeing an
article a while back about how easy it is to crack an encrypted
classloader by replacing one of the classes in rt.jar with a modified
version (the ClassLoader class). If the rt.jar file is indeed sealed,
would this be allowed ? (Isn't there some restriction that every class
in a package must be signed by the same signer?)

Also, is there a way for an application program to determine if it is
indeed running under a JVM whose core library is sealed ? (I remember
trying to call the getSigners() method on ClassLoader.class to check
this out, but if my memory serves me right, it returned null in a JDK1.4
runtime).

The article I am referring to is :

http://www.javaworld.com/javaworld/javaqa/2003-05/01-qa-0509-jcrypt.html

BK
Chris Smith - 13 Sep 2006 05:59 GMT
> One query in connection with that last statement. Remember seeing an
> article a while back about how easy it is to crack an encrypted
> classloader by replacing one of the classes in rt.jar with a modified
> version (the ClassLoader class). If the rt.jar file is indeed sealed,
> would this be allowed ?

It is allowed because you are assuming the ability to replace rt.jar.  
All of the system packages in rt.jar are sealed, but you can replace
rt.jar with a different JAR file where those packages are not sealed.  
Hostile code running within the JVM would not have the ability to
replace the rt.jar file.

The article you quote also mentions JVMPI, which is since superceded by
JVMTI.  These APIs also work, but again are not available to hostile
code running under a SecurityManager.

> (Isn't there some restriction that every class
> in a package must be signed by the same signer?)

Nope.  All that's required is that the line "Sealed: true" in the JAR
manifest.  Package signing is a different matter.  If the JVM loads a
class from a JAR file with "Sealed: true" in the manifest, then it will
ensure that it does not (and has not, in the past) load a class in the
same package from a different JAR file.

> Also, is there a way for an application program to determine if it is
> indeed running under a JVM whose core library is sealed?

If you have a Class object, you can call myClass.getPackage().isSealed()
to find out.  I don't know of a place where that doesn't work.  The API
docs are missing @since tags (infuriatingly common), but I'm sure it's
been around for at least a couple major versions now (1.4 and 1.5, at a
minimum; possibly as old as 1.2).

Signature

Chris Smith

Babu Kalakrishnan - 13 Sep 2006 07:45 GMT
>>(Isn't there some restriction that every class
>>in a package must be signed by the same signer?)
[quoted text clipped - 4 lines]
> ensure that it does not (and has not, in the past) load a class in the
> same package from a different JAR file.

Thanks, I was confused between "Sealed" and "Signed".

Interestingly, I just looked at the manifest.mf file present in the
rt.jar of my JDK distribution - and it doesn't even seem to  have a
"Sealed: true" attribute present.

Is this because the java.* package hierarchy is "sealed" through
extraneous means (by allowing loading only through the bootstrap
classloader) and Sun wants users to be able to replace files in the
javax hierarchy ?

BK
Thomas Hawtin - 13 Sep 2006 08:04 GMT
>> (Isn't there some restriction that every class
>> in a package must be signed by the same signer?)
[quoted text clipped - 4 lines]
> ensure that it does not (and has not, in the past) load a class in the
> same package from a different JAR file.

Assuming a package is not sealed, you can have other class loaders load
classes into the same package namespace. However, those classes will not
have package access rights to the original package. A class loader also
does not allow classes to be defined in the same package (with the same
class loader) with different certificates.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

Chris Uppal - 13 Sep 2006 12:28 GMT
"Chris Smith" <cdsmith@twu.net> wrote in message

> The getfield opcode is checked by the bytecode verifier when the class
> is loaded.  If it tries to access a field to which it doesn't have
> access permission, the verifier will throw a java.lang.VerifyError, and
> the class will fail to load.

The picture is more complicated than that.  For a start, I don't think that
it's the verifier's job to enforce access checks -- they shouldn't fail until
an illegal access is actually executed.

Secondly, the rules for when the JVM will actually enforce access seem to be
somewhat obscure.  I know that it will /sometimes/ do checks, but not always.
And what "sometimes" means has changed over the years.

For instance.  With JDK 1.5.0_06, compile these two files

========== A.java =================
public class A
{
   // NB: deliberately public, despite the name
   public String privateField = "Ooops!";
}
=========== B.java ================
public class B
{
   public static void
   main(String[] args)
   {
       A a = new A();
       System.out.println("OK, here we go...");
       System.out.println(a.privateField);
   }
}
=================================

Then change the declaration of A.privateField to private, and recompile only
A.java.  (All this messing around is just a way to generate bytecode containing
an "illegal" read -- people with convenient access to bytecode generation will
have more straightforward ways of doing it).

Then execute:

   java -cp . B

and it prints:

   OK, here we go...
   Ooops!

OTOH, running java with the "future" argument:

   java -Xfuture -cp . B

and it prints:

   OK, here we go...
   Exception in thread "main" java.lang.IllegalAccessError: tried to access
   field A.privateField from class B
       at B.main(B.java:8)

On the third hand, even without the -Xfuture argument, the current JVM will
(iirc) stop you accessing the internal fields of a String object.  I'm not sure
on what basis it determines that some accesses should be checked and others
not.

As far as I know, /all/ such access should result in the JVM throwing runtime
exceptions, but Sun's JVM's seem to interpret that aspect of the spec a little
loosely...

(And anyway, there's always JNI ;-)

   -- chris
Matt Humphrey - 11 Sep 2006 16:20 GMT
> Why String is immutable? Is there simple explanation I can't find it?

I've seen a number of reasons, although I don't know for certain which of
these the original designers had these in mind:

1) To put Strings on par with Floats, Integers, etc as value objects
specified literally and which cannot be modified by method side-effect.
2) So strings can be easily shared (rather than copying content)
3) So strings can be interned (and tested for equality via ==)
4) They're inherently threadsafe
5) To let them work cleanly as keys in maps without the possibility of
changing
6) To simplify learning the object model
7) So their hashcodes do not have to be recomputed
8) StringBuffer is perfectly good at managing mutable Strings

And, of course, depending on your Security Manager, it is possible (but
never a good idea) to change a String's contents via reflection.

Some results from Google:

http://www.acooke.org/andrew/immutable.html

http://www.programmersheaven.com/2/FAQ-JAVA-String-Is-Immutable

http://en.wikipedia.org/wiki/Immutable_object

Matt Humphrey matth@ivizNOSPAM.com http://www.iviz.com/
Tor Iver Wilhelmsen - 11 Sep 2006 16:41 GMT
> Why String is immutable? Is there simple explanation I can't find it?

Safety (no changing under the covers), efficiency (substring is just a
pointer to the same char array with different indices), reliability as
a hash value. At least.
Arne Vajhøj - 11 Sep 2006 17:04 GMT
> Why String is immutable? Is there simple explanation I can't find it?

Somebody made that choice.

Maybe the following can give you some ideas about why:

http://www.javaworld.com/javaworld/javaqa/2000-06/01-qa-0602-immutable.html
http://www.artima.com/intv/gosling313.html

Arne
Mark Rafn - 11 Sep 2006 19:44 GMT
>Why String is immutable? Is there simple explanation I can't find it?

Don't forget to ask the important further question "when I design a class,
should I make it immutable?".  IMO, the idea of immutable data objects is far
underutilized.

Immutability does a lot of things that aren't obvious at first glance, and you
probably want more of your classes to have these properties:

- sets and maps behave consistently.  Mutable objects can go in and
  later not be findable because their equals() and hashCode() are
  different.
- clarity of intent.  if your object is immutable, you never have to worry
  they'll muck with it when you pass it into someone else's code.  Likewise,
  when they return an immutable object, you don't have to ask yourself
  whether you need to check for value changes or set listeners on properties
  before actually using the object.
- thread safety.  
--
Mark Rafn    dagon@dagon.net    <http://www.dagon.net/>


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.