summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher James Halse Rogers <christopher.halse.rogers@canonical.com>2012-07-02 20:03:30 +1000
committerKristian Høgsberg <krh@bitplanet.net>2012-07-02 13:53:02 -0400
commit161c690b558fff9d0f407311ae4e1fbe389775f7 (patch)
treed09812a18f9c6e198732d10034040bf641ac4c85
parentd2bcffc470cf37dbdeb4d1ed46819360c16d92eb (diff)
protocol: Add explicit nullable types
Most of the time it does not make sense to pass a NULL object, string, or array to a protocol request. This commit adds an explicit “allow-null” attribute to mark the request arguments where NULL makes sense. Passing a NULL object, string, or array to a protocol request which is not marked as allow-null is now an error. An implementation will never receive a NULL value for these arguments from a client. Signed-off-by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
-rw-r--r--src/connection.c81
-rw-r--r--src/scanner.c32
-rw-r--r--tests/connection-test.c87
3 files changed, 188 insertions, 12 deletions
diff --git a/src/connection.c b/src/connection.c
index 72ca908..5946556 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -404,6 +404,36 @@ wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
404 return 0; 404 return 0;
405} 405}
406 406
407struct argument_details {
408 char type;
409 int nullable;
410};
411
412static const char *
413get_next_argument(const char *signature, struct argument_details *details)
414{
415 if (*signature == '?') {
416 details->nullable = 1;
417 signature++;
418 } else
419 details->nullable = 0;
420
421 details->type = *signature;
422 return signature + 1;
423}
424
425static int
426arg_count_for_signature(const char *signature)
427{
428 int count = 0;
429 while (*signature) {
430 if (*signature != '?')
431 count++;
432 signature++;
433 }
434 return count;
435}
436
407struct wl_closure * 437struct wl_closure *
408wl_closure_vmarshal(struct wl_object *sender, 438wl_closure_vmarshal(struct wl_object *sender,
409 uint32_t opcode, va_list ap, 439 uint32_t opcode, va_list ap,
@@ -415,6 +445,8 @@ wl_closure_vmarshal(struct wl_object *sender,
415 int dup_fd; 445 int dup_fd;
416 struct wl_array **arrayp, *array; 446 struct wl_array **arrayp, *array;
417 const char **sp, *s; 447 const char **sp, *s;
448 const char *signature = message->signature;
449 struct argument_details arg;
418 char *extra; 450 char *extra;
419 int i, count, fd, extra_size, *fd_ptr; 451 int i, count, fd, extra_size, *fd_ptr;
420 452
@@ -424,7 +456,7 @@ wl_closure_vmarshal(struct wl_object *sender,
424 return NULL; 456 return NULL;
425 457
426 extra_size = wl_message_size_extra(message); 458 extra_size = wl_message_size_extra(message);
427 count = strlen(message->signature) + 2; 459 count = arg_count_for_signature(signature) + 2;
428 extra = (char *) closure->buffer; 460 extra = (char *) closure->buffer;
429 start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)]; 461 start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)];
430 end = &closure->buffer[256]; 462 end = &closure->buffer[256];
@@ -434,7 +466,9 @@ wl_closure_vmarshal(struct wl_object *sender,
434 closure->types[1] = &ffi_type_pointer; 466 closure->types[1] = &ffi_type_pointer;
435 467
436 for (i = 2; i < count; i++) { 468 for (i = 2; i < count; i++) {
437 switch (message->signature[i - 2]) { 469 signature = get_next_argument(signature, &arg);
470
471 switch (arg.type) {
438 case 'f': 472 case 'f':
439 closure->types[i] = &ffi_type_sint32; 473 closure->types[i] = &ffi_type_sint32;
440 closure->args[i] = p; 474 closure->args[i] = p;
@@ -463,6 +497,10 @@ wl_closure_vmarshal(struct wl_object *sender,
463 extra += sizeof *sp; 497 extra += sizeof *sp;
464 498
465 s = va_arg(ap, const char *); 499 s = va_arg(ap, const char *);
500
501 if (!arg.nullable && s == NULL)
502 goto err_null;
503
466 length = s ? strlen(s) + 1: 0; 504 length = s ? strlen(s) + 1: 0;
467 if (p + DIV_ROUNDUP(length, sizeof *p) + 1 > end) 505 if (p + DIV_ROUNDUP(length, sizeof *p) + 1 > end)
468 goto err; 506 goto err;
@@ -483,6 +521,10 @@ wl_closure_vmarshal(struct wl_object *sender,
483 extra += sizeof *objectp; 521 extra += sizeof *objectp;
484 522
485 object = va_arg(ap, struct wl_object *); 523 object = va_arg(ap, struct wl_object *);
524
525 if (!arg.nullable && object == NULL)
526 goto err_null;
527
486 *objectp = object; 528 *objectp = object;
487 if (end - p < 1) 529 if (end - p < 1)
488 goto err; 530 goto err;
@@ -508,6 +550,10 @@ wl_closure_vmarshal(struct wl_object *sender,
508 extra += sizeof **arrayp; 550 extra += sizeof **arrayp;
509 551
510 array = va_arg(ap, struct wl_array *); 552 array = va_arg(ap, struct wl_array *);
553
554 if (!arg.nullable && array == NULL)
555 goto err_null;
556
511 if (array == NULL || array->size == 0) { 557 if (array == NULL || array->size == 0) {
512 if (end - p < 1) 558 if (end - p < 1)
513 goto err; 559 goto err;
@@ -542,7 +588,7 @@ wl_closure_vmarshal(struct wl_object *sender,
542 break; 588 break;
543 default: 589 default:
544 fprintf(stderr, "unhandled format code: '%c'\n", 590 fprintf(stderr, "unhandled format code: '%c'\n",
545 message->signature[i - 2]); 591 arg.type);
546 assert(0); 592 assert(0);
547 break; 593 break;
548 } 594 }
@@ -567,6 +613,15 @@ err:
567 errno = ENOMEM; 613 errno = ENOMEM;
568 614
569 return NULL; 615 return NULL;
616
617err_null:
618 free(closure);
619 wl_log("error marshalling arguments for %s:%i.%s (signature %s): "
620 "null value passed for arg %i\n",
621 sender->interface->name, sender->id, message->name,
622 message->signature, i);
623 errno = EINVAL;
624 return NULL;
570} 625}
571 626
572struct wl_closure * 627struct wl_closure *
@@ -579,11 +634,13 @@ wl_connection_demarshal(struct wl_connection *connection,
579 int *fd; 634 int *fd;
580 char *extra, **s; 635 char *extra, **s;
581 unsigned int i, count, extra_space; 636 unsigned int i, count, extra_space;
637 const char *signature = message->signature;
638 struct argument_details arg;
582 struct wl_object **object; 639 struct wl_object **object;
583 struct wl_array **array; 640 struct wl_array **array;
584 struct wl_closure *closure; 641 struct wl_closure *closure;
585 642
586 count = strlen(message->signature) + 2; 643 count = arg_count_for_signature(signature) + 2;
587 if (count > ARRAY_LENGTH(closure->types)) { 644 if (count > ARRAY_LENGTH(closure->types)) {
588 printf("too many args (%d)\n", count); 645 printf("too many args (%d)\n", count);
589 errno = EINVAL; 646 errno = EINVAL;
@@ -606,6 +663,8 @@ wl_connection_demarshal(struct wl_connection *connection,
606 end = (uint32_t *) ((char *) p + size); 663 end = (uint32_t *) ((char *) p + size);
607 extra = (char *) end; 664 extra = (char *) end;
608 for (i = 2; i < count; i++) { 665 for (i = 2; i < count; i++) {
666 signature = get_next_argument(signature, &arg);
667
609 if (p + 1 > end) { 668 if (p + 1 > end) {
610 printf("message too short, " 669 printf("message too short, "
611 "object (%d), message %s(%s)\n", 670 "object (%d), message %s(%s)\n",
@@ -614,7 +673,7 @@ wl_connection_demarshal(struct wl_connection *connection,
614 goto err; 673 goto err;
615 } 674 }
616 675
617 switch (message->signature[i - 2]) { 676 switch (arg.type) {
618 case 'u': 677 case 'u':
619 closure->types[i] = &ffi_type_uint32; 678 closure->types[i] = &ffi_type_uint32;
620 closure->args[i] = p++; 679 closure->args[i] = p++;
@@ -784,11 +843,14 @@ copy_fds_to_connection(struct wl_closure *closure,
784{ 843{
785 const struct wl_message *message = closure->message; 844 const struct wl_message *message = closure->message;
786 uint32_t i, count; 845 uint32_t i, count;
846 struct argument_details arg;
847 const char *signature = message->signature;
787 int *fd; 848 int *fd;
788 849
789 count = strlen(message->signature) + 2; 850 count = arg_count_for_signature(signature) + 2;
790 for (i = 2; i < count; i++) { 851 for (i = 2; i < count; i++) {
791 if (message->signature[i - 2] != 'h') 852 signature = get_next_argument(signature, &arg);
853 if (arg.type != 'h')
792 continue; 854 continue;
793 855
794 fd = closure->args[i]; 856 fd = closure->args[i];
@@ -834,6 +896,8 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
834 union wl_value *value; 896 union wl_value *value;
835 int32_t si; 897 int32_t si;
836 int i; 898 int i;
899 struct argument_details arg;
900 const char *signature = closure->message->signature;
837 struct timespec tp; 901 struct timespec tp;
838 unsigned int time; 902 unsigned int time;
839 903
@@ -847,11 +911,12 @@ wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
847 closure->message->name); 911 closure->message->name);
848 912
849 for (i = 2; i < closure->count; i++) { 913 for (i = 2; i < closure->count; i++) {
914 signature = get_next_argument(signature, &arg);
850 if (i > 2) 915 if (i > 2)
851 fprintf(stderr, ", "); 916 fprintf(stderr, ", ");
852 917
853 value = closure->args[i]; 918 value = closure->args[i];
854 switch (closure->message->signature[i - 2]) { 919 switch (arg.type) {
855 case 'u': 920 case 'u':
856 fprintf(stderr, "%u", value->uint32); 921 fprintf(stderr, "%u", value->uint32);
857 break; 922 break;
diff --git a/src/scanner.c b/src/scanner.c
index be8d3d6..4d4537c 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -93,6 +93,7 @@ enum arg_type {
93struct arg { 93struct arg {
94 char *name; 94 char *name;
95 enum arg_type type; 95 enum arg_type type;
96 int nullable;
96 char *interface_name; 97 char *interface_name;
97 struct wl_list link; 98 struct wl_list link;
98 char *summary; 99 char *summary;
@@ -220,6 +221,20 @@ fail(struct parse_context *ctx, const char *msg)
220 exit(EXIT_FAILURE); 221 exit(EXIT_FAILURE);
221} 222}
222 223
224static int
225is_nullable_type(struct arg *arg)
226{
227 switch (arg->type) {
228 /* Strings, objects, and arrays are possibly nullable */
229 case STRING:
230 case OBJECT:
231 case ARRAY:
232 return 1;
233 default:
234 return 0;
235 }
236}
237
223static void 238static void
224start_element(void *data, const char *element_name, const char **atts) 239start_element(void *data, const char *element_name, const char **atts)
225{ 240{
@@ -231,6 +246,7 @@ start_element(void *data, const char *element_name, const char **atts)
231 struct entry *entry; 246 struct entry *entry;
232 struct description *description; 247 struct description *description;
233 const char *name, *type, *interface_name, *value, *summary, *since; 248 const char *name, *type, *interface_name, *value, *summary, *since;
249 const char *allow_null;
234 char *end; 250 char *end;
235 int i, version; 251 int i, version;
236 252
@@ -242,6 +258,7 @@ start_element(void *data, const char *element_name, const char **atts)
242 summary = NULL; 258 summary = NULL;
243 description = NULL; 259 description = NULL;
244 since = NULL; 260 since = NULL;
261 allow_null = NULL;
245 for (i = 0; atts[i]; i += 2) { 262 for (i = 0; atts[i]; i += 2) {
246 if (strcmp(atts[i], "name") == 0) 263 if (strcmp(atts[i], "name") == 0)
247 name = atts[i + 1]; 264 name = atts[i + 1];
@@ -257,6 +274,8 @@ start_element(void *data, const char *element_name, const char **atts)
257 summary = atts[i + 1]; 274 summary = atts[i + 1];
258 if (strcmp(atts[i], "since") == 0) 275 if (strcmp(atts[i], "since") == 0)
259 since = atts[i + 1]; 276 since = atts[i + 1];
277 if (strcmp(atts[i], "allow-null") == 0)
278 allow_null = atts[i + 1];
260 } 279 }
261 280
262 ctx->character_data_length = 0; 281 ctx->character_data_length = 0;
@@ -364,6 +383,16 @@ start_element(void *data, const char *element_name, const char **atts)
364 break; 383 break;
365 } 384 }
366 385
386 if (allow_null == NULL || strcmp(allow_null, "false") == 0)
387 arg->nullable = 0;
388 else if (strcmp(allow_null, "true") == 0)
389 arg->nullable = 1;
390 else
391 fail(ctx, "invalid value for allow-null attribute");
392
393 if (allow_null != NULL && !is_nullable_type(arg))
394 fail(ctx, "allow-null is only valid for objects, strings, and arrays");
395
367 arg->summary = NULL; 396 arg->summary = NULL;
368 if (summary) 397 if (summary)
369 arg->summary = strdup(summary); 398 arg->summary = strdup(summary);
@@ -969,6 +998,9 @@ emit_messages(struct wl_list *message_list,
969 wl_list_for_each(m, message_list, link) { 998 wl_list_for_each(m, message_list, link) {
970 printf("\t{ \"%s\", \"", m->name); 999 printf("\t{ \"%s\", \"", m->name);
971 wl_list_for_each(a, &m->arg_list, link) { 1000 wl_list_for_each(a, &m->arg_list, link) {
1001 if (is_nullable_type(a) && a->nullable)
1002 printf("?");
1003
972 switch (a->type) { 1004 switch (a->type) {
973 default: 1005 default:
974 case INT: 1006 case INT:
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 066b4bc..a852c17 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -233,9 +233,6 @@ TEST(connection_marshal)
233 marshal(&data, "o", 12, &object); 233 marshal(&data, "o", 12, &object);
234 assert(data.buffer[2] == object.id); 234 assert(data.buffer[2] == object.id);
235 235
236 marshal(&data, "o", 12, NULL);
237 assert(data.buffer[2] == 0);
238
239 marshal(&data, "n", 12, &object); 236 marshal(&data, "n", 12, &object);
240 assert(data.buffer[2] == object.id); 237 assert(data.buffer[2] == object.id);
241 238
@@ -252,6 +249,68 @@ TEST(connection_marshal)
252} 249}
253 250
254static void 251static void
252expected_fail_marshal(int expected_error, const char *format, ...)
253{
254 struct wl_closure *closure;
255 static const uint32_t opcode = 4444;
256 static const struct wl_interface test_interface = {
257 .name = "test_object"
258 };
259 static struct wl_object sender = { 0 };
260 struct wl_message message = { "test", format, NULL };
261
262 sender.interface = &test_interface;
263 sender.id = 1234;
264 va_list ap;
265
266 va_start(ap, format);
267 closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
268 va_end(ap);
269
270 assert(closure == NULL);
271 assert(errno == expected_error);
272}
273
274TEST(connection_marshal_nullables)
275{
276 struct marshal_data data;
277 struct wl_object object;
278 struct wl_array array;
279 const char text[] = "curry";
280
281 setup_marshal_data(&data);
282
283 expected_fail_marshal(EINVAL, "o", NULL);
284 expected_fail_marshal(EINVAL, "s", NULL);
285 expected_fail_marshal(EINVAL, "a", NULL);
286
287 marshal(&data, "?o", 12, NULL);
288 assert(data.buffer[2] == 0);
289
290 marshal(&data, "?a", 12, NULL);
291 assert(data.buffer[2] == 0);
292
293 marshal(&data, "?s", 12, NULL);
294 assert(data.buffer[2] == 0);
295
296 object.id = 55293;
297 marshal(&data, "?o", 12, &object);
298 assert(data.buffer[2] == object.id);
299
300 array.data = (void *) text;
301 array.size = sizeof text;
302 marshal(&data, "?a", 20, &array);
303 assert(data.buffer[2] == array.size);
304 assert(memcmp(&data.buffer[3], text, array.size) == 0);
305
306 marshal(&data, "?s", 20, text);
307 assert(data.buffer[2] == sizeof text);
308 assert(strcmp((char *) &data.buffer[3], text) == 0);
309
310 release_marshal_data(&data);
311}
312
313static void
255validate_demarshal_u(struct marshal_data *data, 314validate_demarshal_u(struct marshal_data *data,
256 struct wl_object *object, uint32_t u) 315 struct wl_object *object, uint32_t u)
257{ 316{
@@ -269,7 +328,10 @@ static void
269validate_demarshal_s(struct marshal_data *data, 328validate_demarshal_s(struct marshal_data *data,
270 struct wl_object *object, const char *s) 329 struct wl_object *object, const char *s)
271{ 330{
272 assert(strcmp(data->value.s, s) == 0); 331 if (data->value.s != NULL)
332 assert(strcmp(data->value.s, s) == 0);
333 else
334 assert(s == NULL);
273} 335}
274 336
275static void 337static void
@@ -343,12 +405,25 @@ TEST(connection_demarshal)
343 memcpy(&msg[3], data.value.s, msg[2]); 405 memcpy(&msg[3], data.value.s, msg[2]);
344 demarshal(&data, "s", msg, (void *) validate_demarshal_s); 406 demarshal(&data, "s", msg, (void *) validate_demarshal_s);
345 407
408 data.value.s = "superdude";
409 msg[0] = 400200;
410 msg[1] = 24;
411 msg[2] = 10;
412 memcpy(&msg[3], data.value.s, msg[2]);
413 demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
414
346 data.value.i = wl_fixed_from_double(-90000.2390); 415 data.value.i = wl_fixed_from_double(-90000.2390);
347 msg[0] = 400200; 416 msg[0] = 400200;
348 msg[1] = 12; 417 msg[1] = 12;
349 msg[2] = data.value.i; 418 msg[2] = data.value.i;
350 demarshal(&data, "f", msg, (void *) validate_demarshal_f); 419 demarshal(&data, "f", msg, (void *) validate_demarshal_f);
351 420
421 data.value.s = NULL;
422 msg[0] = 400200;
423 msg[1] = 12;
424 msg[2] = 0;
425 demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
426
352 release_marshal_data(&data); 427 release_marshal_data(&data);
353} 428}
354 429
@@ -408,6 +483,10 @@ TEST(connection_marshal_demarshal)
408 marshal_demarshal(&data, (void *) validate_demarshal_s, 483 marshal_demarshal(&data, (void *) validate_demarshal_s,
409 28, "s", data.value.s); 484 28, "s", data.value.s);
410 485
486 data.value.s = "cookie robots";
487 marshal_demarshal(&data, (void *) validate_demarshal_s,
488 28, "?s", data.value.s);
489
411 data.value.h = mkstemp(f); 490 data.value.h = mkstemp(f);
412 assert(data.value.h >= 0); 491 assert(data.value.h >= 0);
413 marshal_demarshal(&data, (void *) validate_demarshal_h, 492 marshal_demarshal(&data, (void *) validate_demarshal_h,