3131
3232import static java .math .BigInteger .LONG_MASK ;
3333import java .io .IOException ;
34+ import java .io .InvalidObjectException ;
35+ import java .io .ObjectInputStream ;
36+ import java .io .ObjectStreamException ;
37+ import java .io .StreamCorruptedException ;
3438import java .util .Arrays ;
3539import java .util .Objects ;
3640
@@ -1058,6 +1062,15 @@ public BigDecimal(double val, MathContext mc) {
10581062 this .precision = prec ;
10591063 }
10601064
1065+ /**
1066+ * Accept no subclasses.
1067+ */
1068+ private static BigInteger toStrictBigInteger (BigInteger val ) {
1069+ return (val .getClass () == BigInteger .class ) ?
1070+ val :
1071+ new BigInteger (val .toByteArray ().clone ());
1072+ }
1073+
10611074 /**
10621075 * Translates a {@code BigInteger} into a {@code BigDecimal}.
10631076 * The scale of the {@code BigDecimal} is zero.
@@ -1067,8 +1080,8 @@ public BigDecimal(double val, MathContext mc) {
10671080 */
10681081 public BigDecimal (BigInteger val ) {
10691082 scale = 0 ;
1070- intVal = val ;
1071- intCompact = compactValFor (val );
1083+ intVal = toStrictBigInteger ( val ) ;
1084+ intCompact = compactValFor (intVal );
10721085 }
10731086
10741087 /**
@@ -1082,7 +1095,7 @@ public BigDecimal(BigInteger val) {
10821095 * @since 1.5
10831096 */
10841097 public BigDecimal (BigInteger val , MathContext mc ) {
1085- this (val , 0 , mc );
1098+ this (toStrictBigInteger ( val ), 0 , mc );
10861099 }
10871100
10881101 /**
@@ -1096,8 +1109,8 @@ public BigDecimal(BigInteger val, MathContext mc) {
10961109 */
10971110 public BigDecimal (BigInteger unscaledVal , int scale ) {
10981111 // Negative scales are now allowed
1099- this .intVal = unscaledVal ;
1100- this .intCompact = compactValFor (unscaledVal );
1112+ this .intVal = toStrictBigInteger ( unscaledVal ) ;
1113+ this .intCompact = compactValFor (this . intVal );
11011114 this .scale = scale ;
11021115 }
11031116
@@ -1115,6 +1128,7 @@ public BigDecimal(BigInteger unscaledVal, int scale) {
11151128 * @since 1.5
11161129 */
11171130 public BigDecimal (BigInteger unscaledVal , int scale , MathContext mc ) {
1131+ unscaledVal = toStrictBigInteger (unscaledVal );
11181132 long compactVal = compactValFor (unscaledVal );
11191133 int mcp = mc .precision ;
11201134 int prec = 0 ;
@@ -4257,9 +4271,13 @@ private static class UnsafeHolder {
42574271 = unsafe .objectFieldOffset (BigDecimal .class , "intCompact" );
42584272 private static final long intValOffset
42594273 = unsafe .objectFieldOffset (BigDecimal .class , "intVal" );
4274+ private static final long scaleOffset
4275+ = unsafe .objectFieldOffset (BigDecimal .class , "scale" );
42604276
4261- static void setIntCompact (BigDecimal bd , long val ) {
4262- unsafe .putLong (bd , intCompactOffset , val );
4277+ static void setIntValAndScale (BigDecimal bd , BigInteger intVal , int scale ) {
4278+ unsafe .putReference (bd , intValOffset , intVal );
4279+ unsafe .putInt (bd , scaleOffset , scale );
4280+ unsafe .putLong (bd , intCompactOffset , compactValFor (intVal ));
42634281 }
42644282
42654283 static void setIntValVolatile (BigDecimal bd , BigInteger val ) {
@@ -4278,15 +4296,30 @@ static void setIntValVolatile(BigDecimal bd, BigInteger val) {
42784296 @ java .io .Serial
42794297 private void readObject (java .io .ObjectInputStream s )
42804298 throws IOException , ClassNotFoundException {
4281- // Read in all fields
4282- s . defaultReadObject ();
4283- // validate possibly bad fields
4284- if ( intVal == null ) {
4285- String message = "BigDecimal: null intVal in stream" ;
4286- throw new java . io . StreamCorruptedException ( message );
4287- // [all values of scale are now allowed]
4299+ // prepare to read the fields
4300+ ObjectInputStream . GetField fields = s . readFields ();
4301+ BigInteger serialIntVal = ( BigInteger ) fields . get ( "intVal" , null );
4302+
4303+ // Validate field data
4304+ if ( serialIntVal == null ) {
4305+ throw new StreamCorruptedException ( "Null or missing intVal in BigDecimal stream" );
42884306 }
4289- UnsafeHolder .setIntCompact (this , compactValFor (intVal ));
4307+ // Validate provenance of serialIntVal object
4308+ serialIntVal = toStrictBigInteger (serialIntVal );
4309+
4310+ // Any integer value is valid for scale
4311+ int serialScale = fields .get ("scale" , 0 );
4312+
4313+ UnsafeHolder .setIntValAndScale (this , serialIntVal , serialScale );
4314+ }
4315+
4316+ /**
4317+ * Serialization without data not supported for this class.
4318+ */
4319+ @ java .io .Serial
4320+ private void readObjectNoData ()
4321+ throws ObjectStreamException {
4322+ throw new InvalidObjectException ("Deserialized BigDecimal objects need data" );
42904323 }
42914324
42924325 /**
0 commit comments