Repository: lucy-clownfish Updated Branches: refs/heads/master 8bfda8334 -> 5e2478048
Don't allow to subclass final classes Fixes CLOWNFISH-45. Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/5e247804 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/5e247804 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/5e247804 Branch: refs/heads/master Commit: 5e2478048ffc5062dc0a191087e6dfb1e5b87f57 Parents: 5c7144b Author: Nick Wellnhofer <wellnho...@aevum.de> Authored: Fri Jul 24 14:50:36 2015 +0200 Committer: Nick Wellnhofer <wellnho...@aevum.de> Committed: Mon Jul 27 18:26:18 2015 +0200 ---------------------------------------------------------------------- compiler/src/CFCBindCore.c | 1 + compiler/src/CFCBindSpecs.c | 12 ++++++++++-- runtime/core/Clownfish/Class.c | 7 +++++++ runtime/perl/t/binding/019-obj.t | 9 ++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/compiler/src/CFCBindCore.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c index d5f59d7..ce0f9f7 100644 --- a/compiler/src/CFCBindCore.c +++ b/compiler/src/CFCBindCore.c @@ -299,6 +299,7 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) { "\n" "/* Flags for internal use. */\n" "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n" + "#define CFISH_fFINAL 0x00000002\n" ; const char *cfish_defs_2 = "#ifdef CFISH_USE_SHORT_NAMES\n" http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/compiler/src/CFCBindSpecs.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c index f3b377d..4db517b 100644 --- a/compiler/src/CFCBindSpecs.c +++ b/compiler/src/CFCBindSpecs.c @@ -116,6 +116,10 @@ CFCBindSpecs_get_typedefs() { " size_t *parent_offset;\n" "} cfish_InheritedMethSpec;\n" "\n" + "typedef enum {\n" + " cfish_ClassSpec_FINAL = 1\n" + "} cfish_ClassSpecFlags;\n" + "\n" "typedef struct cfish_ClassSpec {\n" " cfish_Class **klass;\n" " cfish_Class **parent;\n" @@ -125,6 +129,7 @@ CFCBindSpecs_get_typedefs() { " uint32_t num_novel_meths;\n" " uint32_t num_overridden_meths;\n" " uint32_t num_inherited_meths;\n" + " uint32_t flags;\n" "} cfish_ClassSpec;\n" "\n"; } @@ -137,6 +142,8 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) { const char *class_var = CFCClass_full_class_var(klass); const char *ivars_offset_name = CFCClass_full_ivars_offset(klass); + const char *flags = CFCClass_final(klass) ? "cfish_ClassSpec_FINAL" : "0"; + char *ivars_size = S_ivars_size(klass); char *parent_ptr = NULL; @@ -200,12 +207,13 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) { " &%s, /* ivars_offset_ptr */\n" " %d, /* num_novel */\n" " %d, /* num_overridden */\n" - " %d /* num_inherited */\n" + " %d, /* num_inherited */\n" + " %s /* flags */\n" " }"; char *class_spec = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name, ivars_size, ivars_offset_name, num_new_novel, - num_new_overridden, num_new_inherited); + num_new_overridden, num_new_inherited, flags); const char *sep = self->num_specs == 0 ? "" : ",\n"; self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/runtime/core/Clownfish/Class.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c index 474e8a2..5f30de2 100644 --- a/runtime/core/Clownfish/Class.c +++ b/runtime/core/Clownfish/Class.c @@ -155,6 +155,9 @@ Class_bootstrap(const cfish_ClassSpec *specs, size_t num_specs, ) { klass->flags |= CFISH_fREFCOUNTSPECIAL; } + if (spec->flags & cfish_ClassSpec_FINAL) { + klass->flags |= CFISH_fFINAL; + } if (parent) { // Copy parent vtable. @@ -266,6 +269,10 @@ Class_init_registry() { static Class* S_simple_subclass(Class *parent, String *name) { + if (parent->flags & CFISH_fFINAL) { + THROW(ERR, "Can't subclass final class %o", Class_Get_Name(parent)); + } + Class *subclass = (Class*)Memory_wrapped_calloc(parent->class_alloc_size, 1); Class_Init_Obj(parent->klass, subclass); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/runtime/perl/t/binding/019-obj.t ---------------------------------------------------------------------- diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t index 5de41df..545b235 100644 --- a/runtime/perl/t/binding/019-obj.t +++ b/runtime/perl/t/binding/019-obj.t @@ -16,7 +16,7 @@ use strict; use warnings; -use Test::More tests => 24; +use Test::More tests => 25; package TestObj; use base qw( Clownfish::Obj ); @@ -57,6 +57,9 @@ use base qw( Clownfish::Test::AliasTestObj ); sub perl_alias {"Perl"} } +package SubclassFinalTestObj; +use base qw( Clownfish::Vector ); + package main; use Storable qw( freeze thaw ); use Clownfish::Test; @@ -152,3 +155,7 @@ my $overridden_alias_test = OverriddenAliasTestObj->new; is( $overridden_alias_test->call_aliased_from_c, 'Perl', 'Overriding aliased methods works' ); +eval { SubclassFinalTestObj->new; }; +like( $@, qr/Can't subclass final class Clownfish::Vector/, + "Final class can't be subclassed" ); +