1
0
Fork 0

fixed handling of empty and reserved attribute names in documents

specifying an empty attribute name in a document may have led to segmentation faults
when the document was unpacked later.
This commit is contained in:
Jan Steemann 2013-03-20 11:48:33 +01:00
parent 609629ead1
commit 40199d64b7
12 changed files with 415 additions and 43 deletions

View File

@ -0,0 +1,163 @@
# coding: utf-8
require 'rspec'
require './arangodb.rb'
describe ArangoDB do
api = "/_api/document"
prefix = "attributes"
context "dealing with attribute names" do
before do
@cn = "UnitTestsCollectionAttributes"
ArangoDB.drop_collection(@cn)
@cid = ArangoDB.create_collection(@cn)
end
after do
ArangoDB.drop_collection(@cn)
end
################################################################################
## creates a document with an empty attribute
################################################################################
it "creates a document with an empty attribute name" do
cmd = api + "?collection=" + @cn
body = "{ \"\" : \"a\", \"foo\" : \"b\" }"
doc = ArangoDB.log_post("#{prefix}-create-empty-name", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
id = doc.parsed_response['_id']
cmd = api + "/" + id
doc = ArangoDB.log_get("#{prefix}-create-empty-name", cmd)
doc.parsed_response.should_not have_key('')
doc.parsed_response.should have_key('foo')
end
################################################################################
## queries a document with an empty attribute
################################################################################
it "queries a document with an empty attribute name" do
cmd = api + "?collection=" + @cn
body = "{ \"\" : \"a\", \"foo\" : \"b\" }"
doc = ArangoDB.log_post("#{prefix}-query-empty-name", cmd, :body => body)
doc.code.should eq(201)
doc.parsed_response['error'].should eq(false)
cmd = "/_api/simple/all"
body = "{ \"collection\" : \"" + @cn + "\" }"
doc = ArangoDB.log_put("#{prefix}-query-empty-name", cmd, :body => body)
documents = doc.parsed_response['result']
documents.length.should eq(1)
documents[0].should_not have_key('')
documents[0].should have_key('foo')
end
################################################################################
## creates a document with reserved attribute names
################################################################################
it "creates a document with reserved attribute names" do
cmd = api + "?collection=" + @cn
body = "{ \"_rev\" : \"99\", \"foo\" : \"002\", \"_id\" : \"meow\", \"_from\" : \"a\", \"_to\" : \"b\", \"_test\" : \"c\", \"meow\" : \"d\" }"
doc = ArangoDB.log_post("#{prefix}-create-reserved-names", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
id = doc.parsed_response['_id']
cmd = api + "/" + id
doc = ArangoDB.log_get("#{prefix}-create-reserved-names", cmd)
doc.parsed_response['_id'].should eq(id)
doc.parsed_response['_rev'].should_not eq('99')
doc.parsed_response.should_not have_key('_from')
doc.parsed_response.should_not have_key('_to')
doc.parsed_response.should_not have_key('_test')
doc.parsed_response.should have_key('meow')
doc.parsed_response['meow'].should eq('d')
doc.parsed_response['foo'].should eq('002')
end
################################################################################
## nested attribute names
################################################################################
it "creates a document with nested attribute names" do
cmd = api + "?collection=" + @cn
body = "{ \"a\" : \"1\", \"b\" : { \"b\" : \"2\" , \"a\" : \"3\", \"\": \"4\", \"_from\": \"5\", \"c\" : 6 } }"
doc = ArangoDB.log_post("#{prefix}-create-duplicate-names", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
id = doc.parsed_response['_id']
cmd = api + "/" + id
doc = ArangoDB.log_get("#{prefix}-create-empty-name", cmd)
doc.parsed_response.should have_key('a')
doc.parsed_response['a'].should eq('1')
doc.parsed_response.should have_key('b')
doc.parsed_response['b'].should_not have_key('')
doc.parsed_response['b'].should_not have_key('_from')
doc.parsed_response['b'].should have_key('b')
doc.parsed_response['b'].should have_key('a')
doc.parsed_response['b'].should have_key('c')
doc.parsed_response['b'].should eq({ "b" => "2", "a" => "3", "c" => 6 })
end
################################################################################
## duplicate attribute names
################################################################################
it "creates a document with duplicate attribute names" do
cmd = api + "?collection=" + @cn
body = "{ \"a\" : \"1\", \"b\" : \"2\", \"a\" : \"3\" }"
doc = ArangoDB.log_post("#{prefix}-create-duplicate-names", cmd, :body => body)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(600)
end
################################################################################
## nested duplicate attribute names
################################################################################
it "creates a document with nested duplicate attribute names" do
cmd = api + "?collection=" + @cn
body = "{ \"a\" : \"1\", \"b\" : { \"b\" : \"2\" , \"c\" : \"3\", \"b\": \"4\" } }"
doc = ArangoDB.log_post("#{prefix}-create-duplicate-names-nested", cmd, :body => body)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(600)
end
end
end

View File

@ -4,6 +4,7 @@ test -d logs || mkdir logs
rspec --color --format d \ rspec --color --format d \
api-http-spec.rb \ api-http-spec.rb \
api-admin-spec.rb \ api-admin-spec.rb \
api-attributes-spec.rb \
api-batch-spec.rb \ api-batch-spec.rb \
api-collection-spec.rb \ api-collection-spec.rb \
api-graph-spec.rb \ api-graph-spec.rb \

View File

@ -210,6 +210,7 @@ endif
################################################################################ ################################################################################
SHELL_COMMON = @top_srcdir@/js/common/tests/shell-require.js \ SHELL_COMMON = @top_srcdir@/js/common/tests/shell-require.js \
@top_srcdir@/js/common/tests/shell-attributes.js \
@top_srcdir@/js/common/tests/shell-document.js \ @top_srcdir@/js/common/tests/shell-document.js \
@top_srcdir@/js/common/tests/shell-edge.js \ @top_srcdir@/js/common/tests/shell-edge.js \
@top_srcdir@/js/common/tests/shell-database.js \ @top_srcdir@/js/common/tests/shell-database.js \

View File

@ -1000,6 +1000,7 @@ static v8::Handle<v8::Value> SaveVocbaseCol (SingleCollectionWriteTransaction<Em
TRI_primary_collection_t* primary = trx->primaryCollection(); TRI_primary_collection_t* primary = trx->primaryCollection();
TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[0], primary->_shaper); TRI_shaped_json_t* shaped = TRI_ShapedJsonV8Object(argv[0], primary->_shaper);
if (! holder.registerShapedJson(primary->_shaper, shaped)) { if (! holder.registerShapedJson(primary->_shaper, shaped)) {
return scope.Close(v8::ThrowException( return scope.Close(v8::ThrowException(
TRI_CreateErrorObject(TRI_errno(), TRI_CreateErrorObject(TRI_errno(),
@ -1999,7 +2000,7 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"<list> must be a list"))); "<list> must be a list")));
} }
// extract objects // extract objects
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(argv[0]); v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(argv[0]);
TRI_json_t* json = TRI_ObjectToJson(array); TRI_json_t* json = TRI_ObjectToJson(array);
@ -6006,10 +6007,11 @@ static v8::Handle<v8::Value> MapGetShapedJson (v8::Local<v8::String> name,
TRI_primary_collection_t* collection = barrier->_container->_collection; TRI_primary_collection_t* collection = barrier->_container->_collection;
// convert the JavaScript string to a string // convert the JavaScript string to a string
string key = TRI_ObjectToString(name); const string key = TRI_ObjectToString(name);
if (key == "") { if (key.size() == 0) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ARANGO_ILLEGAL_NAME, "name must not be empty"))); // we must not throw a v8 exception here because this will cause follow up errors
return scope.Close(v8::Handle<v8::Value>());
} }
if (TRI_IsSystemCollectionName(key.c_str())) { if (TRI_IsSystemCollectionName(key.c_str())) {
@ -6020,9 +6022,6 @@ static v8::Handle<v8::Value> MapGetShapedJson (v8::Local<v8::String> name,
TRI_shaper_t* shaper = collection->_shaper; TRI_shaper_t* shaper = collection->_shaper;
TRI_shape_pid_t pid = shaper->findAttributePathByName(shaper, key.c_str()); TRI_shape_pid_t pid = shaper->findAttributePathByName(shaper, key.c_str());
// TRI_shape_sid_t sid;
// TRI_EXTRACT_SHAPE_IDENTIFIER_MARKER(sid, marker);
TRI_shaped_json_t document; TRI_shaped_json_t document;
TRI_EXTRACT_SHAPED_JSON_MARKER(document, marker); TRI_EXTRACT_SHAPED_JSON_MARKER(document, marker);
@ -6040,7 +6039,8 @@ static v8::Handle<v8::Value> MapGetShapedJson (v8::Local<v8::String> name,
} }
} }
else { else {
return scope.Close(v8::ThrowException(v8::String::New("cannot extract attribute"))); // we must not throw a v8 exception here because this will cause follow up errors
return scope.Close(v8::Handle<v8::Value>());
} }
} }

View File

@ -193,6 +193,10 @@ static int TraditionalGenerate (TRI_key_generator_t* const generator,
// user key is too long // user key is too long
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD; return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
} }
else if (userKeyLength == 0) {
// user key is empty
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
}
// validate user-supplied key // validate user-supplied key
if (regexec(&data->_regex, userKey, 0, NULL, 0) != 0) { if (regexec(&data->_regex, userKey, 0, NULL, 0) != 0) {

View File

@ -483,7 +483,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
var quoteSingleJsonCharacter = function (c) { var quoteSingleJsonCharacter = function (c) {
if (characterQuoteCache.hasOwnProperty[c]) { if (characterQuoteCache.hasOwnProperty(c)) {
return characterQuoteCache[c]; return characterQuoteCache[c];
} }

View File

@ -483,7 +483,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
var quoteSingleJsonCharacter = function (c) { var quoteSingleJsonCharacter = function (c) {
if (characterQuoteCache.hasOwnProperty[c]) { if (characterQuoteCache.hasOwnProperty(c)) {
return characterQuoteCache[c]; return characterQuoteCache[c];
} }

View File

@ -0,0 +1,188 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief test attribute naming
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var arangodb = require("org/arangodb");
var db = arangodb.db;
var wait = require("internal").wait;
// -----------------------------------------------------------------------------
// --SECTION-- attributes
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test attributes
////////////////////////////////////////////////////////////////////////////////
function AttributesSuite () {
var cn = "UnitTestsCollectionAttributes";
var c = null;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
db._drop(cn);
c = db._create(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
c.unload();
c.drop();
c = null;
wait(0.0);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief no attributes
////////////////////////////////////////////////////////////////////////////////
testNoAttributes : function () {
var doc = { };
var d1 = c.save(doc);
var d2 = c.document(d1._id);
delete d1.error;
assertEqual(d1, d2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief empty attribute name
////////////////////////////////////////////////////////////////////////////////
testEmptyAttribute : function () {
var doc = { "" : "foo" };
var d1 = c.save(doc);
var d2 = c.document(d1._id);
delete d1.error;
var i;
for (i in d2) {
if (d2.hasOwnProperty(i)) {
assertTrue(i !== "");
}
}
assertEqual(d1, d2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief query empty attribute name
////////////////////////////////////////////////////////////////////////////////
testQueryEmptyAttribute : function () {
var doc = { "" : "foo" };
c.save(doc);
var docs = c.toArray();
assertEqual(1, docs.length);
var d = docs[0];
var i;
for (i in d) {
if (d.hasOwnProperty(i)) {
assertTrue(i !== "");
}
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief reserved attribute names
////////////////////////////////////////////////////////////////////////////////
testReservedAttributes : function () {
var doc = { "_id" : "foo", "_rev": "99", "_key" : "meow", "_from" : "33", "_to": "99", "_test" : false };
var d1 = c.save(doc);
var d2 = c.document(d1._id);
assertEqual("meow", d1._key);
assertEqual("meow", d2._key);
assertEqual(cn + "/meow", d1._id);
assertEqual(cn + "/meow", d2._id);
assertEqual(d1._rev, d2._rev);
// user specified _rev value must have been ignored
assertTrue(d1._rev !== "99");
// test attributes
var i;
for (i in d2) {
if (d2.hasOwnProperty(i)) {
assertTrue(i !== "_from" && i !== "_to" && i !== "_test");
}
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief attribute name with special chars
////////////////////////////////////////////////////////////////////////////////
testSpecialAttributes : function () {
var doc = { "-meow-" : 1, "mötör" : 2, " " : 3, "\t" : 4, "\r" : 5, "\n" : 6 };
var d1 = c.save(doc);
var d2 = c.document(d1._id);
assertEqual(1, d2["-meow-"]);
assertEqual(2, d2["mötör"]);
assertEqual(3, d2[" "]);
assertEqual(4, d2["\t"]);
assertEqual(5, d2["\r"]);
assertEqual(6, d2["\n"]);
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(AttributesSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -89,7 +89,6 @@ typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t; typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t; typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t; typedef uint32_t flex_uint32_t;
typedef uint64_t flex_uint64_t;
#else #else
typedef signed char flex_int8_t; typedef signed char flex_int8_t;
typedef short int flex_int16_t; typedef short int flex_int16_t;
@ -213,11 +212,6 @@ typedef void* yyscan_t;
typedef struct yy_buffer_state *YY_BUFFER_STATE; typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif #endif
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2 #define EOB_ACT_LAST_MATCH 2
@ -240,6 +234,11 @@ typedef size_t yy_size_t;
#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE #ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state struct yy_buffer_state
@ -257,7 +256,7 @@ struct yy_buffer_state
/* Number of characters read into yy_ch_buf, not including EOB /* Number of characters read into yy_ch_buf, not including EOB
* characters. * characters.
*/ */
yy_size_t yy_n_chars; int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it, /* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to * and can realloc() it to grow it, and should free() it to
@ -336,7 +335,7 @@ static void tri_jsp__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscann
YY_BUFFER_STATE tri_jsp__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); YY_BUFFER_STATE tri_jsp__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
YY_BUFFER_STATE tri_jsp__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE tri_jsp__scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
YY_BUFFER_STATE tri_jsp__scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); YY_BUFFER_STATE tri_jsp__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
void *tri_jsp_alloc (yy_size_t ,yyscan_t yyscanner ); void *tri_jsp_alloc (yy_size_t ,yyscan_t yyscanner );
void *tri_jsp_realloc (void *,yy_size_t ,yyscan_t yyscanner ); void *tri_jsp_realloc (void *,yy_size_t ,yyscan_t yyscanner );
@ -387,7 +386,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
*/ */
#define YY_DO_BEFORE_ACTION \ #define YY_DO_BEFORE_ACTION \
yyg->yytext_ptr = yy_bp; \ yyg->yytext_ptr = yy_bp; \
yyleng = (yy_size_t) (yy_cp - yy_bp); \ yyleng = (size_t) (yy_cp - yy_bp); \
yyg->yy_hold_char = *yy_cp; \ yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \ *yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp; yyg->yy_c_buf_p = yy_cp;
@ -566,8 +565,8 @@ struct yyguts_t
size_t yy_buffer_stack_max; /**< capacity of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */
YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
char yy_hold_char; char yy_hold_char;
yy_size_t yy_n_chars; int yy_n_chars;
yy_size_t yyleng_r; int yyleng_r;
char *yy_c_buf_p; char *yy_c_buf_p;
int yy_init; int yy_init;
int yy_start; int yy_start;
@ -614,7 +613,7 @@ FILE *tri_jsp_get_out (yyscan_t yyscanner );
void tri_jsp_set_out (FILE * out_str ,yyscan_t yyscanner ); void tri_jsp_set_out (FILE * out_str ,yyscan_t yyscanner );
yy_size_t tri_jsp_get_leng (yyscan_t yyscanner ); int tri_jsp_get_leng (yyscan_t yyscanner );
char *tri_jsp_get_text (yyscan_t yyscanner ); char *tri_jsp_get_text (yyscan_t yyscanner );
@ -673,7 +672,7 @@ static int input (yyscan_t yyscanner );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \ { \
int c = '*'; \ int c = '*'; \
yy_size_t n; \ int n; \
for ( n = 0; n < max_size && \ for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \ buf[n] = (char) c; \
@ -1129,7 +1128,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else else
{ {
yy_size_t num_to_read = int num_to_read =
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
while ( num_to_read <= 0 ) while ( num_to_read <= 0 )
@ -1143,7 +1142,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
if ( b->yy_is_our_buffer ) if ( b->yy_is_our_buffer )
{ {
yy_size_t new_size = b->yy_buf_size * 2; int new_size = b->yy_buf_size * 2;
if ( new_size <= 0 ) if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8; b->yy_buf_size += b->yy_buf_size / 8;
@ -1174,7 +1173,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
/* Read in more data. */ /* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
yyg->yy_n_chars, num_to_read ); yyg->yy_n_chars, (int) num_to_read );
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
} }
@ -1299,7 +1298,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else else
{ /* need more input */ { /* need more input */
yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
++yyg->yy_c_buf_p; ++yyg->yy_c_buf_p;
switch ( yy_get_next_buffer( yyscanner ) ) switch ( yy_get_next_buffer( yyscanner ) )
@ -1323,7 +1322,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
case EOB_ACT_END_OF_FILE: case EOB_ACT_END_OF_FILE:
{ {
if ( tri_jsp_wrap(yyscanner ) ) if ( tri_jsp_wrap(yyscanner ) )
return 0; return EOF;
if ( ! yyg->yy_did_buffer_switch_on_eof ) if ( ! yyg->yy_did_buffer_switch_on_eof )
YY_NEW_FILE; YY_NEW_FILE;
@ -1585,7 +1584,7 @@ void tri_jsp_pop_buffer_state (yyscan_t yyscanner)
*/ */
static void tri_jsp_ensure_buffer_stack (yyscan_t yyscanner) static void tri_jsp_ensure_buffer_stack (yyscan_t yyscanner)
{ {
yy_size_t num_to_alloc; int num_to_alloc;
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if (!yyg->yy_buffer_stack) { if (!yyg->yy_buffer_stack) {
@ -1683,11 +1682,12 @@ YY_BUFFER_STATE tri_jsp__scan_string (yyconst char * yystr , yyscan_t yyscanner)
* @param yyscanner The scanner object. * @param yyscanner The scanner object.
* @return the newly allocated buffer state object. * @return the newly allocated buffer state object.
*/ */
YY_BUFFER_STATE tri_jsp__scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) YY_BUFFER_STATE tri_jsp__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
{ {
YY_BUFFER_STATE b; YY_BUFFER_STATE b;
char *buf; char *buf;
yy_size_t n, i; yy_size_t n;
int i;
/* Get memory for full buffer, including space for trailing EOB's. */ /* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2; n = _yybytes_len + 2;
@ -1797,7 +1797,7 @@ FILE *tri_jsp_get_out (yyscan_t yyscanner)
/** Get the length of the current token. /** Get the length of the current token.
* @param yyscanner The scanner object. * @param yyscanner The scanner object.
*/ */
yy_size_t tri_jsp_get_leng (yyscan_t yyscanner) int tri_jsp_get_leng (yyscan_t yyscanner)
{ {
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
return yyleng; return yyleng;
@ -2184,7 +2184,7 @@ static TRI_json_t* ParseArray (yyscan_t scanner) {
// do proper unescaping // do proper unescaping
name = TRI_UnescapeUtf8StringZ(yyextra._memoryZone, yytext + 1, nameLen, &outLength); name = TRI_UnescapeUtf8StringZ(yyextra._memoryZone, yytext + 1, nameLen, &outLength);
nameLen = outLength;
} }
else if (c == STRING_CONSTANT_ASCII) { else if (c == STRING_CONSTANT_ASCII) {
// ASCII-only attribute name // ASCII-only attribute name

View File

@ -286,7 +286,7 @@ static TRI_json_t* ParseArray (yyscan_t scanner) {
// do proper unescaping // do proper unescaping
name = TRI_UnescapeUtf8StringZ(yyextra._memoryZone, yytext + 1, nameLen, &outLength); name = TRI_UnescapeUtf8StringZ(yyextra._memoryZone, yytext + 1, nameLen, &outLength);
nameLen = outLength;
} }
else if (c == STRING_CONSTANT_ASCII) { else if (c == STRING_CONSTANT_ASCII) {
// ASCII-only attribute name // ASCII-only attribute name

View File

@ -310,6 +310,8 @@ static int WeightShapeType (TRI_shape_type_t type) {
case TRI_SHAPE_HOMOGENEOUS_LIST: return 900; case TRI_SHAPE_HOMOGENEOUS_LIST: return 900;
} }
LOG_ERROR("invalid shape type: %d\n", (int) type);
assert(false); assert(false);
return 0; return 0;
} }
@ -780,8 +782,8 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_shape_value_t* dst, T
char* ptr; char* ptr;
// sanity checks // sanity checks
assert(json->_type == TRI_JSON_ARRAY); TRI_ASSERT_DEBUG(json->_type == TRI_JSON_ARRAY);
assert(json->_value._objects._length % 2 == 0); TRI_ASSERT_DEBUG(json->_value._objects._length % 2 == 0);
// number of attributes // number of attributes
n = json->_value._objects._length / 2; n = json->_value._objects._length / 2;
@ -805,6 +807,17 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_shape_value_t* dst, T
key = TRI_AtVector(&json->_value._objects, 2 * i); key = TRI_AtVector(&json->_value._objects, 2 * i);
val = TRI_AtVector(&json->_value._objects, 2 * i + 1); val = TRI_AtVector(&json->_value._objects, 2 * i + 1);
TRI_ASSERT_DEBUG(key != NULL);
TRI_ASSERT_DEBUG(val != NULL);
if (key->_value._string.data == NULL ||
key->_value._string.length == 1 ||
key->_value._string.data[0] == '_') {
// empty or reserved attribute name
p--;
continue;
}
// first find an identifier for the name // first find an identifier for the name
p->_aid = shaper->findAttributeName(shaper, key->_value._string.data); p->_aid = shaper->findAttributeName(shaper, key->_value._string.data);
@ -841,6 +854,9 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_shape_value_t* dst, T
// add variable offset table size // add variable offset table size
total += (v + 1) * sizeof(TRI_shape_size_t); total += (v + 1) * sizeof(TRI_shape_size_t);
// now adjust n because we might have excluded empty attributes
n = f + v;
// now sort the shape entries // now sort the shape entries
TRI_SortShapeValues(values, n); TRI_SortShapeValues(values, n);

View File

@ -289,8 +289,6 @@ static bool FillShapeValueList (TRI_shaper_t* shaper,
return false; return false;
} }
memset(values, 0, sizeof(TRI_shape_value_t) * n);
total = 0; total = 0;
e = values + n; e = values + n;
@ -592,7 +590,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper,
// first find an identifier for the name // first find an identifier for the name
TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key); TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key);
if (*keyStr == 0) { if (*keyStr == 0 || keyStr.length() == 0) {
--p; --p;
continue; continue;
} }
@ -789,13 +787,12 @@ static bool FillShapeValueJson (TRI_shaper_t* shaper,
return FillShapeValueNull(shaper, dst); return FillShapeValueNull(shaper, dst);
} }
} }
seenObjects.push_back(o);
} }
else { else {
seenHashes.insert(hash); seenHashes.insert(hash);
seenObjects.push_back(o);
} }
seenObjects.push_back(o);
} }
if (json->IsNull()) { if (json->IsNull()) {
@ -1439,6 +1436,7 @@ TRI_json_t* TRI_ObjectToJson (v8::Handle<v8::Value> parameter) {
const uint32_t n = arrayParameter->Length(); const uint32_t n = arrayParameter->Length();
TRI_json_t* listJson = TRI_CreateList2Json(TRI_UNKNOWN_MEM_ZONE, (const size_t) n); TRI_json_t* listJson = TRI_CreateList2Json(TRI_UNKNOWN_MEM_ZONE, (const size_t) n);
if (listJson != 0) { if (listJson != 0) {
for (uint32_t j = 0; j < n; ++j) { for (uint32_t j = 0; j < n; ++j) {
v8::Handle<v8::Value> item = arrayParameter->Get(j); v8::Handle<v8::Value> item = arrayParameter->Get(j);
@ -1458,9 +1456,10 @@ TRI_json_t* TRI_ObjectToJson (v8::Handle<v8::Value> parameter) {
const uint32_t n = names->Length(); const uint32_t n = names->Length();
TRI_json_t* arrayJson = TRI_CreateArray2Json(TRI_UNKNOWN_MEM_ZONE, (const size_t) n); TRI_json_t* arrayJson = TRI_CreateArray2Json(TRI_UNKNOWN_MEM_ZONE, (const size_t) n);
if (arrayJson != 0) { if (arrayJson != 0) {
for (uint32_t j = 0; j < n; ++j) { for (uint32_t j = 0; j < n; ++j) {
v8::Handle<v8::Value> key = names->Get(j); v8::Handle<v8::Value> key = names->Get(j);
v8::Handle<v8::Value> item = arrayParameter->Get(key); v8::Handle<v8::Value> item = arrayParameter->Get(key);
TRI_json_t* result = TRI_ObjectToJson(item); TRI_json_t* result = TRI_ObjectToJson(item);