Attempt to sort out versioning of archives/DO to be more tolerant/flexible.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35118 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2012-04-27 11:58:56 +00:00
parent e970570954
commit f4e2de3057
6 changed files with 189 additions and 48 deletions

View file

@ -1,3 +1,22 @@
2012-02-28 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSArchiver.m:
* Source/NSUnarchiver.m:
* Source/NSPortCoder.m:
* Source/Coder.m:
Updates to cope with the fact that some BSD ports of gnustep-base
used incorrect versioning, and that people have released Gorm
files with versioning incompatible with current releases.
1. dissociate coder -systemVersion from the actual system version,
so that if people mess with the gnustep-base version, their
non-standard releases will still interoperate with normal code.
2. Implement new array encoding/decoding compatible with earlier
versions (except if the array contains exactly 0xffffffff items).
3. Raise exception if decoding archives with an unsupported version.
4. Add GSCoderSystemVersion user default to override the system
version used for encoding ... for testing and tweaking to generate
archives in, or communicate with DO servers using an earlier version.
2012-04-23 Fred Kiefer <FredKiefer@gmx.de> 2012-04-23 Fred Kiefer <FredKiefer@gmx.de>
* Tests/base/NSAutoreleasePool/autorelease_eh.m: * Tests/base/NSAutoreleasePool/autorelease_eh.m:

View file

@ -254,20 +254,17 @@ static Class NSMutableDataMallocClass;
count: (NSUInteger)count count: (NSUInteger)count
at: (const void*)buf at: (const void*)buf
{ {
unsigned c = count; uint32_t c;
uint8_t bytes[20]; uint8_t bytes[20];
uint8_t *bytePtr = 0; uint8_t *bytePtr = 0;
uint8_t byteCount = 0; uint8_t byteCount = 0;
NSUInteger i; NSUInteger i;
NSUInteger offset = 0; NSUInteger offset = 0;
unsigned size = objc_sizeof_type(type); uint32_t size = objc_sizeof_type(type);
uint32_t version = [self systemVersion];
uchar info; uchar info;
/* The array count is encoded as a sequence of bytes containing 7bits of if (12402 == version)
* data and using the eighth (top) bit to indicate that there are more
* bytes in the sequence.
*/
if ([self systemVersion] > 12401)
{ {
NSUInteger tmp = count; NSUInteger tmp = count;
@ -280,6 +277,21 @@ static Class NSMutableDataMallocClass;
} }
bytePtr = &bytes[sizeof(bytes) - byteCount]; bytePtr = &bytes[sizeof(bytes) - byteCount];
} }
else
{
/* We normally store the count as a 32bit integer ... but if it's
* very big, we store 0xffffffff and then an additional 64bit value
* containing the actual count.
*/
if (count >= 0xffffffff)
{
c = 0xffffffff;
}
else
{
c = count;
}
}
switch (*type) switch (*type)
{ {
@ -308,17 +320,21 @@ static Class NSMutableDataMallocClass;
if (_initialPass == NO) if (_initialPass == NO)
{ {
(*_tagImp)(_dst, tagSel, _GSC_ARY_B); (*_tagImp)(_dst, tagSel, _GSC_ARY_B);
if (0 == byteCount) if (12402 == version)
{
(*_serImp)(_dst, serSel, &c, @encode(unsigned), nil);
}
else
{ {
for (i = 0; i < byteCount; i++) for (i = 0; i < byteCount; i++)
{ {
(*_serImp)(_dst, serSel, bytePtr + i, @encode(uint8_t), nil); (*_serImp)(_dst, serSel, bytePtr + i, @encode(uint8_t), nil);
} }
} }
else
{
(*_serImp)(_dst, serSel, &c, @encode(uint32_t), nil);
if (0xffffffff == c)
{
(*_serImp)(_dst, serSel, &count, @encode(NSUInteger), nil);
}
}
} }
for (i = 0; i < c; i++) for (i = 0; i < c; i++)
@ -330,17 +346,21 @@ static Class NSMutableDataMallocClass;
else if (_initialPass == NO) else if (_initialPass == NO)
{ {
(*_tagImp)(_dst, tagSel, _GSC_ARY_B); (*_tagImp)(_dst, tagSel, _GSC_ARY_B);
if (0 == byteCount) if (12402 == version)
{
(*_serImp)(_dst, serSel, &c, @encode(unsigned), nil);
}
else
{ {
for (i = 0; i < byteCount; i++) for (i = 0; i < byteCount; i++)
{ {
(*_serImp)(_dst, serSel, bytePtr + i, @encode(uint8_t), nil); (*_serImp)(_dst, serSel, bytePtr + i, @encode(uint8_t), nil);
} }
} }
else
{
(*_serImp)(_dst, serSel, &c, @encode(uint32_t), nil);
if (0xffffffff == c)
{
(*_serImp)(_dst, serSel, &count, @encode(NSUInteger), nil);
}
}
(*_tagImp)(_dst, tagSel, info); (*_tagImp)(_dst, tagSel, info);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)

View file

@ -36,14 +36,42 @@
#import "Foundation/NSData.h" #import "Foundation/NSData.h"
#import "Foundation/NSCoder.h" #import "Foundation/NSCoder.h"
#import "Foundation/NSSerialization.h" #import "Foundation/NSSerialization.h"
#import "Foundation/NSUserDefaults.h"
#import "GNUstepBase/NSObject+GNUstepBase.h" #import "GNUstepBase/NSObject+GNUstepBase.h"
@implementation NSCoder @implementation NSCoder
/* We used to use a system version which actually reflected the version
* of GNUstep-base ... but people screwed that up by releasing versions
* of base with unofficial version numbers conflicting with the scheme.
* So ... we are now starting from a basepoint of 1 million ... on the
* basis that the old numbering scheme derived from the gnustep-base
* major.minor.subminor versioning (in which each can range from 0 to 99)
* should not have allowed anyone to create an archive with a version
* greater than 999999.
* In future, the system version will change if (and only if) the format
* of the encoded data changes.
*/
#define MAX_SUPPORTED_SYSTEM_VERSION 1000000
static unsigned systemVersion = MAX_SUPPORTED_SYSTEM_VERSION;
+ (void) initialize + (void) initialize
{ {
if (self == [NSCoder class]) if (self == [NSCoder class])
{ {
unsigned sv;
/* The GSCoderSystemVersion user default is provided for testing
* and to allow new code to communicate (via Distributed Objects)
* with systems running older versions.
*/
sv = [[NSUserDefaults standardUserDefaults]
integerForKey: @"GSCoderSystemVersion"];
if (sv > 0 && sv <= MAX_SUPPORTED_SYSTEM_VERSION)
{
systemVersion = sv;
}
} }
} }
@ -298,8 +326,7 @@
- (unsigned) systemVersion - (unsigned) systemVersion
{ {
return (((GNUSTEP_BASE_MAJOR_VERSION * 100) return systemVersion;
+ GNUSTEP_BASE_MINOR_VERSION) * 100) + GNUSTEP_BASE_SUBMINOR_VERSION;
} }

View file

@ -351,10 +351,16 @@ static IMP _eSerImp; /* Method to serialize with. */
static IMP _eTagImp; /* Serialize a type tag. */ static IMP _eTagImp; /* Serialize a type tag. */
static IMP _xRefImp; /* Serialize a crossref. */ static IMP _xRefImp; /* Serialize a crossref. */
static unsigned encodingVersion;
+ (void) initialize + (void) initialize
{ {
if (self == [NSPortCoder class]) if (self == [NSPortCoder class])
{ {
NSCoder *coder = [NSCoder new];
encodingVersion = [coder systemVersion];
[coder release];
#if GS_WITH_GC #if GS_WITH_GC
/* We create a typed memory descriptor for map nodes. /* We create a typed memory descriptor for map nodes.
*/ */
@ -435,12 +441,12 @@ static IMP _xRefImp; /* Serialize a crossref. */
{ {
NSUInteger i; NSUInteger i;
NSUInteger offset = 0; NSUInteger offset = 0;
unsigned size = objc_sizeof_type(type); uint32_t size = objc_sizeof_type(type);
unsigned char info; unsigned char info;
NSUInteger count; NSUInteger count;
(*_dTagImp)(_src, dTagSel, &info, 0, &_cursor); (*_dTagImp)(_src, dTagSel, &info, 0, &_cursor);
if (_version > 12401) if (12402 == _version)
{ {
uint8_t c; uint8_t c;
@ -469,10 +475,15 @@ static IMP _xRefImp; /* Serialize a crossref. */
} }
else else
{ {
unsigned c; uint32_t c;
(*_dDesImp)(_src, dDesSel, &c, @encode(unsigned), &_cursor, nil); (*_dDesImp)(_src, dDesSel, &c, @encode(uint32_t), &_cursor, nil);
count = c; count = c;
if (0xffffffff == c)
{
(*_dDesImp)(_src, dDesSel,
&count, @encode(NSUInteger), &_cursor, nil);
}
} }
if (info != _GSC_ARY_B) if (info != _GSC_ARY_B)
{ {
@ -1135,19 +1146,16 @@ static IMP _xRefImp; /* Serialize a crossref. */
at: (const void*)buf at: (const void*)buf
{ {
NSUInteger i; NSUInteger i;
unsigned c = count; uint32_t c = count;
uint8_t bytes[20]; uint8_t bytes[20];
uint8_t *bytePtr = 0; uint8_t *bytePtr = 0;
uint8_t byteCount = 0; uint8_t byteCount = 0;
NSUInteger offset = 0; NSUInteger offset = 0;
unsigned size = objc_sizeof_type(type); uint32_t size = objc_sizeof_type(type);
uint32_t version = [self systemVersion];
uchar info; uchar info;
/* The array count is encoded as a sequence of bytes containing 7bits of if (12402 == version)
* data and using the eighth (top) bit to indicate that there are more
* bytes in the sequence.
*/
if ([self systemVersion] > 12401)
{ {
NSUInteger tmp = count; NSUInteger tmp = count;
@ -1160,6 +1168,21 @@ static IMP _xRefImp; /* Serialize a crossref. */
} }
bytePtr = &bytes[sizeof(bytes) - byteCount]; bytePtr = &bytes[sizeof(bytes) - byteCount];
} }
else
{
/* We normally store the count as a 32bit integer ... but if it's
* very big, we store 0xffffffff and then an additional 64bit value
* containing the actual count.
*/
if (count >= 0xffffffff)
{
c = 0xffffffff;
}
else
{
c = count;
}
}
switch (*type) switch (*type)
{ {
@ -1188,11 +1211,7 @@ static IMP _xRefImp; /* Serialize a crossref. */
if (_initialPass == NO) if (_initialPass == NO)
{ {
(*_eTagImp)(_dst, eTagSel, _GSC_ARY_B); (*_eTagImp)(_dst, eTagSel, _GSC_ARY_B);
if (0 == byteCount) if (12402 == version)
{
(*_eSerImp)(_dst, eSerSel, &c, @encode(unsigned), nil);
}
else
{ {
for (i = 0; i < byteCount; i++) for (i = 0; i < byteCount; i++)
{ {
@ -1200,6 +1219,14 @@ static IMP _xRefImp; /* Serialize a crossref. */
(_dst, eSerSel, bytePtr + i, @encode(uint8_t), nil); (_dst, eSerSel, bytePtr + i, @encode(uint8_t), nil);
} }
} }
else
{
(*_eSerImp)(_dst, eSerSel, &c, @encode(uint32_t), nil);
if (0xffffffff == c)
{
(*_eSerImp)(_dst, eSerSel, &count, @encode(NSUInteger), nil);
}
}
} }
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
@ -1210,17 +1237,21 @@ static IMP _xRefImp; /* Serialize a crossref. */
else if (_initialPass == NO) else if (_initialPass == NO)
{ {
(*_eTagImp)(_dst, eTagSel, _GSC_ARY_B); (*_eTagImp)(_dst, eTagSel, _GSC_ARY_B);
if (0 == byteCount) if (12402 == version)
{
(*_eSerImp)(_dst, eSerSel, &c, @encode(unsigned), nil);
}
else
{ {
for (i = 0; i < byteCount; i++) for (i = 0; i < byteCount; i++)
{ {
(*_eSerImp)(_dst, eSerSel, bytePtr + i, @encode(uint8_t), nil); (*_eSerImp)(_dst, eSerSel, bytePtr + i, @encode(uint8_t), nil);
} }
} }
else
{
(*_eSerImp)(_dst, eSerSel, &c, @encode(unsigned), nil);
if (0xffffffff == c)
{
(*_eSerImp)(_dst, eSerSel, &count, @encode(NSUInteger), nil);
}
}
(*_eTagImp)(_dst, eTagSel, info); (*_eTagImp)(_dst, eTagSel, info);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
@ -1920,6 +1951,12 @@ static IMP _xRefImp; /* Serialize a crossref. */
objects: &sizeO objects: &sizeO
pointers: &sizeP]; pointers: &sizeP];
if (_version > encodingVersion)
{
[NSException raise: NSInvalidArgumentException
format: @"Message systemVersion (%u) not recognised", _version];
}
/* /*
* Allocate and initialise arrays to build crossref maps in. * Allocate and initialise arrays to build crossref maps in.
*/ */

View file

@ -398,16 +398,22 @@ mapClassName(NSUnarchiverObjectInfo *info)
@implementation NSUnarchiver @implementation NSUnarchiver
static Class NSDataMallocClass; static Class NSDataMallocClass;
static unsigned encodingVersion;
+ (void) initialize + (void) initialize
{ {
if ([self class] == [NSUnarchiver class]) if ([self class] == [NSUnarchiver class])
{ {
NSArchiver *archiver = [NSArchiver new];
encodingVersion = [archiver systemVersion];
[archiver release];
desSel = @selector(deserializeDataAt:ofObjCType:atCursor:context:); desSel = @selector(deserializeDataAt:ofObjCType:atCursor:context:);
tagSel = @selector(deserializeTypeTag:andCrossRef:atCursor:); tagSel = @selector(deserializeTypeTag:andCrossRef:atCursor:);
dValSel = @selector(decodeValueOfObjCType:at:); dValSel = @selector(decodeValueOfObjCType:at:);
clsDict = [[NSMutableDictionary alloc] initWithCapacity: 200]; clsDict = [[NSMutableDictionary alloc] initWithCapacity: 200];
NSDataMallocClass = [NSDataMalloc class]; NSDataMallocClass = [NSDataMalloc class];
} }
} }
@ -536,7 +542,7 @@ static Class NSDataMallocClass;
NSUInteger count; NSUInteger count;
(*tagImp)(src, tagSel, &info, 0, &cursor); (*tagImp)(src, tagSel, &info, 0, &cursor);
if ([self systemVersion] > 12401) if ([self systemVersion] == 12402)
{ {
uint8_t c; uint8_t c;
@ -565,10 +571,14 @@ static Class NSDataMallocClass;
} }
else else
{ {
unsigned c; uint32_t c;
(*desImp)(src, desSel, &c, @encode(unsigned), &cursor, nil); (*desImp)(src, desSel, &c, @encode(uint32_t), &cursor, nil);
count = c; count = c;
if (0xffffffff == c)
{
(*desImp)(src, desSel, &count, @encode(NSUInteger), &cursor, nil);
}
} }
if (info != _GSC_ARY_B) if (info != _GSC_ARY_B)
{ {
@ -1524,6 +1534,11 @@ static Class NSDataMallocClass;
classes: &sizeC classes: &sizeC
objects: &sizeO objects: &sizeO
pointers: &sizeP]; pointers: &sizeP];
if (version > encodingVersion)
{
[NSException raise: NSInvalidArgumentException
format: @"Archive systemVersion (%u) not recognised", version];
}
if (clsMap == 0) if (clsMap == 0)
{ {

View file

@ -4,13 +4,36 @@
* might be from an earlier build. * might be from an earlier build.
*/ */
// disable extensions ... we want to use standard code /* disable extensions ... we want to use standard code
*/
#ifdef _GNU_SOURCE #ifdef _GNU_SOURCE
#undef _GNU_SOURCE #undef _GNU_SOURCE
#endif #endif
/* Ensure we have _XOPEN_SOURCE turned on at the appropriate
* level for the facilities we need.
*
* Minimum of 600 for string.h so we get the POSIX strerror_r() behavior
*/
#if defined(_XOPEN_SOURCE)
#if _XOPEN_SOURCE < 600
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
#else
#define _XOPEN_SOURCE 600
#endif
#import "config.h" #import "config.h"
#if defined(HAVE_STRING_H)
/* For POSIX strerror_r()
*/
#include <string.h>
#endif
#include <errno.h>
/* If this is included in a file in the Additions subdirectory, and we are /* If this is included in a file in the Additions subdirectory, and we are
* building for use with the NeXT/Apple Foundation, then we need to import * building for use with the NeXT/Apple Foundation, then we need to import
* the native headers in preference to any of our own. * the native headers in preference to any of our own.