From 4597541a6819f7c9248acd41c319498fcd364572 Mon Sep 17 00:00:00 2001 From: Nicola Pero Date: Tue, 22 Feb 2011 18:30:44 +0000 Subject: [PATCH] Fixed check for flexible array members used in Objective-C instance variables From-SVN: r170412 --- gcc/objc/ChangeLog | 17 ++++-- gcc/objc/objc-act.c | 109 +++++++++++++++++++++++++++++------- gcc/testsuite/ChangeLog | 7 +++ gcc/testsuite/objc.dg/type-size-3.m | 6 +- gcc/testsuite/objc.dg/type-size-4.m | 23 ++++++++ gcc/testsuite/objc.dg/type-size-5.m | 22 ++++++++ 6 files changed, 156 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/objc.dg/type-size-4.m create mode 100644 gcc/testsuite/objc.dg/type-size-5.m diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index a7b21c322c0..9c466aa8771 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,13 +1,22 @@ +2011-02-22 Nicola Pero + + PR objc/47832 + * objc-act.c (flexible_array_type_p): New. + (add_instance_variable): Produce an error if an instance variable + uses flexible array members. + (encode_array): Do not emit an error if encoding a flexible array + type while generating instance variables. + 2011-02-21 Mike Stump * Make-lang.in (check_objc_parallelize): Refine for 4 processor machines. 2011-02-20 Nicola Pero - * objc-gnu-runtime-abi-01.c (TARGET_64BIT): Removed. Removed - usage of padding fields. Do not include tm.h. - * objc-act.c (objc_write_global_declaration): Set input_location - to BUILTINS_LOCATION while generating runtime metadata. + * objc-gnu-runtime-abi-01.c (TARGET_64BIT): Removed. Removed + usage of padding fields. Do not include tm.h. + * objc-act.c (objc_write_global_declaration): Set input_location + to BUILTINS_LOCATION while generating runtime metadata. 2011-01-20 Nicola Pero diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index a91c7083173..85ef8fb0526 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -5925,6 +5925,58 @@ add_category (tree klass, tree category) } } +#ifndef OBJCPLUS +/* A flexible array member is a C99 extension where you can use + "type[]" at the end of a struct to mean a variable-length array. + + In Objective-C, instance variables are fundamentally members of a + struct, but the struct can always be extended by subclassing; hence + we need to detect and forbid all instance variables declared using + flexible array members. + + No check for this is needed in Objective-C++, since C++ does not + have flexible array members. */ + +/* Determine whether TYPE is a structure with a flexible array member, + a union containing such a structure (possibly recursively) or an + array of such structures or unions. These are all invalid as + instance variable. */ +static bool +flexible_array_type_p (tree type) +{ + tree x; + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + x = TYPE_FIELDS (type); + if (x == NULL_TREE) + return false; + while (DECL_CHAIN (x) != NULL_TREE) + x = DECL_CHAIN (x); + if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE + && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) + return true; + return false; + case UNION_TYPE: + for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x)) + { + if (flexible_array_type_p (TREE_TYPE (x))) + return true; + } + return false; + /* Note that we also check for arrays of something that uses a flexible array member. */ + case ARRAY_TYPE: + if (flexible_array_type_p (TREE_TYPE (type))) + return true; + return false; + default: + return false; + } +} +#endif + /* Called after parsing each instance variable declaration. Necessary to preserve typedefs and implement public/private... @@ -5958,6 +6010,27 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility, return klass; } +#ifndef OBJCPLUS + /* Also, in C reject a struct with a flexible array member. Ie, + + struct A { int x; int[] y; }; + + @interface X + { + struct A instance_variable; + } + @end + + is not valid because if the class is subclassed, we wouldn't be able + to calculate the offset of the next instance variable. */ + if (flexible_array_type_p (field_type)) + { + error ("instance variable %qs uses flexible array member", ivar_name); + /* Return class as is without adding this ivar. */ + return klass; + } +#endif + #ifdef OBJCPLUS /* Check if the ivar being added has a non-POD C++ type. If so, we will need to either (1) warn the user about it or (2) generate suitable @@ -9926,27 +9999,23 @@ encode_array (tree type, int curtype, int format) if (an_int_cst == NULL) { /* We are trying to encode an incomplete array. An incomplete - array is forbidden as part of an instance variable. */ - if (generating_instance_variables) - { - /* TODO: Detect this error earlier. */ - error ("instance variable has unknown size"); - return; - } + array is forbidden as part of an instance variable; but it + may occur if the instance variable is a pointer to such an + array. */ - /* So the only case in which an incomplete array could occur is - if we are encoding the arguments or return value of a method. - In that case, an incomplete array argument or return value - (eg, -(void)display: (char[])string) is treated like a - pointer because that is how the compiler does the function - call. A special, more complicated case, is when the - incomplete array is the last member of a struct (eg, if we - are encoding "struct { unsigned long int a;double b[];}"), - which is again part of a method argument/return value. In - that case, we really need to communicate to the runtime that - there is an incomplete array (not a pointer!) there. So, we - detect that special case and encode it as a zero-length - array. + /* So the only case in which an incomplete array could occur + (without being pointed to) is if we are encoding the + arguments or return value of a method. In that case, an + incomplete array argument or return value (eg, + -(void)display: (char[])string) is treated like a pointer + because that is how the compiler does the function call. A + special, more complicated case, is when the incomplete array + is the last member of a struct (eg, if we are encoding + "struct { unsigned long int a;double b[];}"), which is again + part of a method argument/return value. In that case, we + really need to communicate to the runtime that there is an + incomplete array (not a pointer!) there. So, we detect that + special case and encode it as a zero-length array. Try to detect that we are part of a struct. We do this by searching for '=' in the type encoding for the current type. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 33c8ddeefad..32604613064 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2011-02-22 Nicola Pero + + PR objc/47832 + * objc.dg/type-size-3.m: Updated error message. + * objc.dg/type-size-4.m: New test. + * objc.dg/type-size-5.m: New test. + 2011-02-22 Rainer Orth * lib/gnat.exp: Fix comments. diff --git a/gcc/testsuite/objc.dg/type-size-3.m b/gcc/testsuite/objc.dg/type-size-3.m index 6d7fe038447..bc66b0be67a 100644 --- a/gcc/testsuite/objc.dg/type-size-3.m +++ b/gcc/testsuite/objc.dg/type-size-3.m @@ -1,4 +1,4 @@ -/* Reject ivars with an unknown size. */ +/* Reject ivars that use flexible array members. */ /* Contributed by Nicola Pero */ /* { dg-do compile } */ @@ -10,11 +10,9 @@ typedef struct @interface Test { - test_type c; + test_type c; /* { dg-error "instance variable .c. uses flexible array member" } */ } @end @implementation Test @end - -/* { dg-error "instance variable has unknown size" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/objc.dg/type-size-4.m b/gcc/testsuite/objc.dg/type-size-4.m new file mode 100644 index 00000000000..7e26da34a43 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-4.m @@ -0,0 +1,23 @@ +/* Allow ivars that are pointers to structs with an unknown size. */ +/* Contributed by Nicola Pero */ +/* PR objc/47832 */ +/* { dg-do compile } */ + +typedef struct +{ + unsigned long int a; + double b[]; +} test_type; + +@interface Test +{ + /* These are all fine. */ + double *a; + struct { int x; double y[]; } *b; + test_type *c; + union union_type { int x; test_type y; } *d; +} +@end + +@implementation Test +@end diff --git a/gcc/testsuite/objc.dg/type-size-5.m b/gcc/testsuite/objc.dg/type-size-5.m new file mode 100644 index 00000000000..d89af32b452 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-5.m @@ -0,0 +1,22 @@ +/* Reject ivars that use flexible array members. */ +/* Contributed by Nicola Pero */ +/* { dg-do compile } */ + +typedef struct +{ + unsigned long int a; + double b[]; +} test_type; + +@interface Test +{ + double a[]; /* { dg-error "instance variable .a. has unknown size" } */ + struct { int x; double y[]; } b; /* { dg-error "instance variable .b. uses flexible array member" } */ + test_type c; /* { dg-error "instance variable .c. uses flexible array member" } */ + test_type d[4]; /* { dg-error "instance variable .d. uses flexible array member" } */ + union union_type { int x; test_type y; } e; /* { dg-error "instance variable .e. uses flexible array member" } */ +} +@end + +@implementation Test +@end -- 2.11.4.GIT