Compare commits

...
Author SHA1 Message Date
seandeelywoods 25e0db6058 Merging in changes from trunk 2013-03-18 12:41:14 +00:00
hypnotoad c01a65e62d Bug fix for 3598385
dict exists now throws an error if an invalid dict is encountered,
according to the same rules as exists prior to January 2012 
(Checkin [22ec97b057])

This patch includes fixes for both the bytecode compiled version
of dict exists, the non-bytecode version of dict exists, and
updates as well as several new cases for the dict regression tests

The patch for dict.test checks both the compiled and non-compiled
versions of the dict exists command
2012-12-31 20:39:31 +00:00
3 changed files with 240 additions and 74 deletions
+14 -7
View File
@@ -2002,22 +2002,29 @@ DictExistsCmd(
int objc,
Tcl_Obj *const *objv)
{
int result;
Tcl_Obj *dictPtr, *valuePtr;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary key ?key ...?");
return TCL_ERROR;
}
dictPtr = TclTraceDictPath(interp, objv[1], objc-3, objv+2,
DICT_PATH_EXISTS);
if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT
|| Tcl_DictObjGet(interp, dictPtr, objv[objc-1],
&valuePtr) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
} else {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));
if (dictPtr == NULL) {
return TCL_ERROR;
}
if (dictPtr == DICT_PATH_NON_EXISTENT) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
return TCL_OK;
}
result=Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr);
if(result!=TCL_OK) {
return result;
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));
return TCL_OK;
}
+190 -59
View File
@@ -6183,23 +6183,16 @@ TEBCresume(
TRACE_APPEND(("OK\n"));
NEXT_INST_F(1, 1, 0);
case INST_DICT_GET:
case INST_DICT_EXISTS: {
case INST_DICT_GET: {
register Tcl_Interp *interp2 = interp;
opnd = TclGetUInt4AtPtr(pc+1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
if (*pc == INST_DICT_EXISTS) {
interp2 = NULL;
}
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp2, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
if (dictPtr == NULL) {
if (*pc == INST_DICT_EXISTS) {
goto dictNotExists;
}
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%s\": ",
O2S(OBJ_AT_DEPTH(opnd))),
@@ -6209,11 +6202,6 @@ TEBCresume(
}
if (Tcl_DictObjGet(interp2, dictPtr, OBJ_AT_TOS,
&objResultPtr) == TCL_OK) {
if (*pc == INST_DICT_EXISTS) {
objResultPtr = TCONST(objResultPtr ? 1 : 0);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
}
if (objResultPtr) {
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
@@ -6227,21 +6215,181 @@ TEBCresume(
CACHE_STACK_INFO();
TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp));
} else {
if (*pc == INST_DICT_EXISTS) {
dictNotExists:
objResultPtr = TCONST(0);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
}
TRACE_WITH_OBJ((
"%u => ERROR reading leaf dictionary key \"%s\": ",
opnd, O2S(dictPtr)), Tcl_GetObjResult(interp));
}
goto gotError;
}
case INST_DICT_EXISTS: {
register Tcl_Interp *interp2 = interp;
opnd = TclGetUInt4AtPtr(pc+1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp2, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_EXISTS);
if (dictPtr == DICT_PATH_NON_EXISTENT) {
objResultPtr = TCONST(0);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
}
if (dictPtr == NULL) {
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%s\": ",
O2S(OBJ_AT_DEPTH(opnd))),
Tcl_GetObjResult(interp));
goto gotError;
}
}
if (Tcl_DictObjGet(interp2, dictPtr, OBJ_AT_TOS,
&objResultPtr) == TCL_OK) {
objResultPtr = TCONST(objResultPtr ? 1 : 0);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
} else {
TRACE_WITH_OBJ((
"%u => ERROR reading leaf dictionary key \"%s\": ",
opnd, O2S(dictPtr)), Tcl_GetObjResult(interp));
}
goto gotError;
}
case INST_DICT_SET:
opnd = TclGetUInt4AtPtr(pc+1);
opnd2 = TclGetUInt4AtPtr(pc+5);
varPtr = LOCAL(opnd2);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u %u => ", opnd, opnd2));
if (TclIsVarDirectReadable(varPtr)) {
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
TclNewObj(dictPtr);
allocateDict = 1;
} else {
allocateDict = Tcl_IsShared(dictPtr);
if (allocateDict) {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
}
cleanup = opnd + 1;
result = Tcl_DictObjPutKeyList(interp, dictPtr, opnd,
&OBJ_AT_DEPTH(opnd), OBJ_AT_TOS);
if (result != TCL_OK) {
if (allocateDict) {
TclDecrRefCount(dictPtr);
}
TRACE_WITH_OBJ(("%u %u => ERROR updating dictionary: ",
opnd, opnd2), Tcl_GetObjResult(interp));
goto checkForCatch;
}
if (TclIsVarDirectWritable(varPtr)) {
if (allocateDict) {
value2Ptr = varPtr->value.objPtr;
Tcl_IncrRefCount(dictPtr);
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
}
varPtr->value.objPtr = dictPtr;
}
objResultPtr = dictPtr;
} else {
Tcl_IncrRefCount(dictPtr);
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
CACHE_STACK_INFO();
TclDecrRefCount(dictPtr);
if (objResultPtr == NULL) {
TRACE_APPEND(("ERROR: %.30s\n",
O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
}
#ifndef TCL_COMPILE_DEBUG
if (*(pc+9) == INST_POP) {
NEXT_INST_V(10, cleanup, 0);
}
#endif
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(9, cleanup, 1);
case INST_DICT_UNSET:
opnd = TclGetUInt4AtPtr(pc+1);
opnd2 = TclGetUInt4AtPtr(pc+5);
varPtr = LOCAL(opnd2);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u %u => ", opnd, opnd2));
if (TclIsVarDirectReadable(varPtr)) {
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
TclNewObj(dictPtr);
allocateDict = 1;
} else {
allocateDict = Tcl_IsShared(dictPtr);
if (allocateDict) {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
}
cleanup = opnd;
result = Tcl_DictObjRemoveKeyList(interp, dictPtr, opnd,
&OBJ_AT_DEPTH(opnd-1));
if (result != TCL_OK) {
if (allocateDict) {
TclDecrRefCount(dictPtr);
}
TRACE_WITH_OBJ(("%u %u => ERROR updating dictionary: ",
opnd, opnd2), Tcl_GetObjResult(interp));
goto checkForCatch;
}
if (TclIsVarDirectWritable(varPtr)) {
if (allocateDict) {
value2Ptr = varPtr->value.objPtr;
Tcl_IncrRefCount(dictPtr);
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
}
varPtr->value.objPtr = dictPtr;
}
objResultPtr = dictPtr;
} else {
Tcl_IncrRefCount(dictPtr);
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
CACHE_STACK_INFO();
TclDecrRefCount(dictPtr);
if (objResultPtr == NULL) {
TRACE_APPEND(("ERROR: %.30s\n",
O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
}
#ifndef TCL_COMPILE_DEBUG
if (*(pc+9) == INST_POP) {
NEXT_INST_V(10, cleanup, 0);
}
#endif
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(9, cleanup, 1);
case INST_DICT_INCR_IMM:
opnd = TclGetUInt4AtPtr(pc+1);
opnd2 = TclGetUInt4AtPtr(pc+5);
@@ -6268,45 +6416,28 @@ TEBCresume(
}
}
switch (*pc) {
case INST_DICT_SET:
cleanup = opnd + 1;
result = Tcl_DictObjPutKeyList(interp, dictPtr, opnd,
&OBJ_AT_DEPTH(opnd), OBJ_AT_TOS);
break;
case INST_DICT_INCR_IMM:
cleanup = 1;
opnd = TclGetInt4AtPtr(pc+1);
result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &valuePtr);
if (result != TCL_OK) {
break;
}
if (valuePtr == NULL) {
Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS,Tcl_NewIntObj(opnd));
} else {
value2Ptr = Tcl_NewIntObj(opnd);
Tcl_IncrRefCount(value2Ptr);
if (Tcl_IsShared(valuePtr)) {
valuePtr = Tcl_DuplicateObj(valuePtr);
Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, valuePtr);
}
result = TclIncrObj(interp, valuePtr, value2Ptr);
if (result == TCL_OK) {
TclInvalidateStringRep(dictPtr);
}
TclDecrRefCount(value2Ptr);
}
break;
case INST_DICT_UNSET:
cleanup = opnd;
result = Tcl_DictObjRemoveKeyList(interp, dictPtr, opnd,
&OBJ_AT_DEPTH(opnd-1));
break;
default:
cleanup = 0; /* stop compiler warning */
Tcl_Panic("Should not happen!");
}
cleanup = 1;
opnd = TclGetInt4AtPtr(pc+1);
result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &valuePtr);
if (result != TCL_OK) {
break;
}
if (valuePtr == NULL) {
Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS,Tcl_NewIntObj(opnd));
} else {
value2Ptr = Tcl_NewIntObj(opnd);
Tcl_IncrRefCount(value2Ptr);
if (Tcl_IsShared(valuePtr)) {
valuePtr = Tcl_DuplicateObj(valuePtr);
Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, valuePtr);
}
result = TclIncrObj(interp, valuePtr, value2Ptr);
if (result == TCL_OK) {
TclInvalidateStringRep(dictPtr);
}
TclDecrRefCount(value2Ptr);
}
if (result != TCL_OK) {
if (allocateDict) {
TclDecrRefCount(dictPtr);
+36 -8
View File
@@ -227,18 +227,46 @@ test dict-8.6 {dict size command} -returnCodes error -body {
dict size a
} -result {missing value to go with key}
test dict-9.1 {dict exists command} {dict exists {a b} a} 1
test dict-9.2 {dict exists command} {dict exists {a b} b} 0
test dict-9.3 {dict exists command} {dict exists {a {b c}} a b} 1
test dict-9.4 {dict exists command} {dict exists {a {b c}} a c} 0
test dict-9.5 {dict exists command} {dict exists {a {b c}} b c} 0
test dict-9.6 {dict exists command} {dict exists {a {b c d}} a c} 0
test dict-9.7 {dict exists command} -returnCodes error -body {
test dict-9.1 {dict exists command} {dict exists {a b} a} 1
test dict-9.2 {dict exists command} {dict exists {a b} b} 0
test dict-9.3 {dict exists command} {dict exists {a {b c}} a b} 1
test dict-9.4 {dict exists command} {dict exists {a {b c}} a c} 0
test dict-9.5 {dict exists command} {dict exists {a {b c}} b c} 0
test dict-9.6 {dict exists command} -returnCodes error -body {
dict exists {a {b c d}} a c
} -result {missing value to go with key}
test dict-9.7 {dict exists command} -returnCodes error -body {
dict exists
} -result {wrong # args: should be "dict exists dictionary key ?key ...?"}
test dict-9.8 {dict exists command} -returnCodes error -body {
test dict-9.8 {dict exists command} -returnCodes error -body {
dict exists {}
} -result {wrong # args: should be "dict exists dictionary key ?key ...?"}
test dict-9.9 {dict exists command} {dict exists {} any} 0
test dict-9.10 {dict exists command} -returnCodes error -body {
dict exists any any
} -result {missing value to go with key}
# Repeat for non-bytecode compiled implementation
set cmd dict
test dict-9.1n {dict exists command (non-compiled)} {$cmd exists {a b} a} 1
test dict-9.2n {dict exists command (non-compiled)} {$cmd exists {a b} b} 0
test dict-9.3n {dict exists command (non-compiled)} {$cmd exists {a {b c}} a b} 1
test dict-9.4n {dict exists command (non-compiled)} {$cmd exists {a {b c}} a c} 0
test dict-9.5n {dict exists command (non-compiled)} {$cmd exists {a {b c}} b c} 0
test dict-9.6n {dict exists command (non-compiled)} -returnCodes error -body {
$cmd exists {a {b c d}} a c
} -result {missing value to go with key}
test dict-9.7n {dict exists command (non-compiled)} -returnCodes error -body {
$cmd exists
} -result {wrong # args: should be "dict exists dictionary key ?key ...?"}
test dict-9.8n {dict exists command (non-compiled)} -returnCodes error -body {
$cmd exists {}
} -result {wrong # args: should be "dict exists dictionary key ?key ...?"}
test dict-9.9n {dict exists command (non-compiled)} {$cmd exists {} any} 0
test dict-9.10n {dict exists command (non-compiled)} -returnCodes error -body {
$cmd exists any any
} -result {missing value to go with key}
test dict-10.1 {dict info command} -body {
# Actual string returned by this command is undefined; it is