Changeset 249608 in webkit


Ignore:
Timestamp:
Sep 6, 2019 10:42:11 PM (5 years ago)
Author:
mark.lam@apple.com
Message:

Harden protection of the Gigacage Config parameters.
https://bugs.webkit.org/show_bug.cgi?id=201570
<rdar://problem/55134229>

Reviewed by Saam Barati.

Source/bmalloc:

  1. Rename protectGigacageBasePtrs() and unprotectGigacageBasePtrs() to freezeGigacageConfig() and unfreezeGigacageConfig() respectively.

Also move the alignment check in protectGigacageBasePtrs() into ensureGigacage().
There's no need to check it more than once.

  1. Introduce permanentlyFreezeGigacageConfig() which permanently makes the Config ReadOnly. Once invoked, the Config cannot be made writable again.

This is made possible by using vm_protect with a true set_maximum argument.
We also add a g_gigacageConfig.isPermanentlyFrozen flag that we assert.
Note: this permanence is only true for OS(DARWIN) since vm_protect is Mach API.

  1. Rename disableDisablingPrimitiveGigacageIfShouldBeEnabled() to forbidDisablingPrimitiveGigacage() because "disablingDisabling" is a tongue twister.

Also, we don't want to make it conditional on "IfShouldBeEnabled". We want
forbidDisablingPrimitiveGigacage() to be irreversible. It is up to the client
to ensure that the Gigacage is already initialized (if possible) before
invoking forbidDisablingPrimitiveGigacage(). Conceptually, the forbidding
isn't about guaranteeing that the Gigacage is enabled. It only takes away the
option to disable it.

That said, forbidDisablingPrimitiveGigacage() is only invoked by clients that
care about keeping the Gigacage enabled. So, it does a sanity check (with an
assertion) that if !GIGACAGE_ALLOCATION_CAN_FAIL, then the Gigacage should be
have been initialized and enabled before invoking it.

We also make sure that forbidDisablingPrimitiveGigacage() calls
permanentlyFreezeGigacageConfig() unconditionally. It is safe to call it more
than once. This guarantees that the Config is permanently frozen after this,
even if a bug should inadvertantly set the
g_gigacageConfig.disablingPrimitiveGigacageIsForbidden flag before
forbidDisablingPrimitiveGigacage() is invoked.

  1. Assert that ensureGigacage() is only called once.
  1. Assert that shouldBeEnabled() is only called once. Also moved its cached result into the Config so that it can be frozen.
  • bmalloc/Gigacage.cpp:

(Gigacage::bmalloc::freezeGigacageConfig):
(Gigacage::bmalloc::unfreezeGigacageConfig):
(Gigacage::bmalloc::permanentlyFreezeGigacageConfig):
(Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope):
(Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope):
(Gigacage::ensureGigacage):
(Gigacage::disablePrimitiveGigacage):
(Gigacage::verifyGigacageIsEnabled):
(Gigacage::forbidDisablingPrimitiveGigacage):
(Gigacage::isDisablingPrimitiveGigacageForbidden):
(Gigacage::shouldBeEnabled):
(Gigacage::bmalloc::protectGigacageBasePtrs): Deleted.
(Gigacage::bmalloc::unprotectGigacageBasePtrs): Deleted.
(Gigacage::bmalloc::UnprotectGigacageBasePtrsScope::UnprotectGigacageBasePtrsScope): Deleted.
(Gigacage::bmalloc::UnprotectGigacageBasePtrsScope::~UnprotectGigacageBasePtrsScope): Deleted.
(Gigacage::primitiveGigacageDisabled): Deleted.
(Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled): Deleted.
(Gigacage::isDisablingPrimitiveGigacageDisabled): Deleted.

  • bmalloc/Gigacage.h:

(Gigacage::isPrimitiveGigacagePermanentlyEnabled):
(Gigacage::canPrimitiveGigacageBeDisabled):
(Gigacage::forbidDisablingPrimitiveGigacage):
(Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled): Deleted.

Source/JavaScriptCore:

Just renaming some function names here.

  • assembler/testmasm.cpp:

(JSC::testCagePreservesPACFailureBit):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::cageConditionally):

  • jsc.cpp:

(jscmain):

Source/WebKit:

Just renaming a function name here.

  • WebProcess/WebProcess.cpp:

Source/WTF:

Just renaming some function names here.

  • wtf/Gigacage.h:

(Gigacage::forbidDisablingPrimitiveGigacage):
(Gigacage::isDisablingPrimitiveGigacageForbidden):
(Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled): Deleted.
(Gigacage::isDisablingPrimitiveGigacageDisabled): Deleted.

Location:
trunk/Source
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r249597 r249608  
     12019-09-06  Mark Lam  <mark.lam@apple.com>
     2
     3        Harden protection of the Gigacage Config parameters.
     4        https://bugs.webkit.org/show_bug.cgi?id=201570
     5        <rdar://problem/55134229>
     6
     7        Reviewed by Saam Barati.
     8
     9        Just renaming some function names here.
     10
     11        * assembler/testmasm.cpp:
     12        (JSC::testCagePreservesPACFailureBit):
     13        * jit/AssemblyHelpers.h:
     14        (JSC::AssemblyHelpers::cageConditionally):
     15        * jsc.cpp:
     16        (jscmain):
     17
    1182019-09-06  Ross Kirsling  <ross.kirsling@sony.com>
    219
  • trunk/Source/JavaScriptCore/assembler/testmasm.cpp

    r249576 r249608  
    12111211{
    12121212#if GIGACAGE_ENABLED
    1213     ASSERT(!Gigacage::isDisablingPrimitiveGigacageDisabled());
     1213    ASSERT(!Gigacage::isDisablingPrimitiveGigacageForbidden());
    12141214    auto cage = compile([] (CCallHelpers& jit) {
    12151215        emitFunctionPrologue(jit);
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r249556 r249608  
    15891589#if GIGACAGE_ENABLED
    15901590        if (Gigacage::isEnabled(kind)) {
    1591             if (kind != Gigacage::Primitive || Gigacage::isDisablingPrimitiveGigacageDisabled())
     1591            if (kind != Gigacage::Primitive || Gigacage::isDisablingPrimitiveGigacageForbidden())
    15921592                cageWithoutUntagging(kind, storage);
    15931593            else {
  • trunk/Source/JavaScriptCore/jsc.cpp

    r249175 r249608  
    30873087    JSC::Wasm::enableFastMemory();
    30883088#endif
    3089     Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled();
     3089    Gigacage::forbidDisablingPrimitiveGigacage();
    30903090
    30913091#if PLATFORM(COCOA)
  • trunk/Source/WTF/ChangeLog

    r249556 r249608  
     12019-09-06  Mark Lam  <mark.lam@apple.com>
     2
     3        Harden protection of the Gigacage Config parameters.
     4        https://bugs.webkit.org/show_bug.cgi?id=201570
     5        <rdar://problem/55134229>
     6
     7        Reviewed by Saam Barati.
     8
     9        Just renaming some function names here.
     10
     11        * wtf/Gigacage.h:
     12        (Gigacage::forbidDisablingPrimitiveGigacage):
     13        (Gigacage::isDisablingPrimitiveGigacageForbidden):
     14        (Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled): Deleted.
     15        (Gigacage::isDisablingPrimitiveGigacageDisabled): Deleted.
     16
    1172019-09-05  Mark Lam  <mark.lam@apple.com>
    218
  • trunk/Source/WTF/wtf/Gigacage.h

    r249556 r249608  
    5050inline void removePrimitiveDisableCallback(void (*)(void*), void*) { }
    5151
    52 inline void disableDisablingPrimitiveGigacageIfShouldBeEnabled() { }
     52inline void forbidDisablingPrimitiveGigacage() { }
    5353
    54 inline bool isDisablingPrimitiveGigacageDisabled() { return false; }
     54inline bool isDisablingPrimitiveGigacageForbidden() { return false; }
    5555inline bool isPrimitiveGigacagePermanentlyEnabled() { return false; }
    5656inline bool canPrimitiveGigacageBeDisabled() { return true; }
  • trunk/Source/WebKit/ChangeLog

    r249605 r249608  
     12019-09-06  Mark Lam  <mark.lam@apple.com>
     2
     3        Harden protection of the Gigacage Config parameters.
     4        https://bugs.webkit.org/show_bug.cgi?id=201570
     5        <rdar://problem/55134229>
     6
     7        Reviewed by Saam Barati.
     8
     9        Just renaming a function name here.
     10
     11        * WebProcess/WebProcess.cpp:
     12
    1132019-09-06  Wenson Hsieh  <wenson_hsieh@apple.com>
    214
  • trunk/Source/WebKit/WebProcess/WebProcess.cpp

    r249603 r249608  
    221221#endif
    222222   
    223     Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled();
     223    Gigacage::forbidDisablingPrimitiveGigacage();
    224224}
    225225
  • trunk/Source/bmalloc/ChangeLog

    r249588 r249608  
     12019-09-06  Mark Lam  <mark.lam@apple.com>
     2
     3        Harden protection of the Gigacage Config parameters.
     4        https://bugs.webkit.org/show_bug.cgi?id=201570
     5        <rdar://problem/55134229>
     6
     7        Reviewed by Saam Barati.
     8
     9        1. Rename protectGigacageBasePtrs() and unprotectGigacageBasePtrs() to
     10           freezeGigacageConfig() and unfreezeGigacageConfig() respectively.
     11
     12           Also move the alignment check in protectGigacageBasePtrs() into ensureGigacage().
     13           There's no need to check it more than once.
     14
     15        2. Introduce permanentlyFreezeGigacageConfig() which permanently makes the
     16           Config ReadOnly.  Once invoked, the Config cannot be made writable again.
     17
     18           This is made possible by using vm_protect with a true set_maximum argument.
     19           We also add a g_gigacageConfig.isPermanentlyFrozen flag that we assert.
     20           Note: this permanence is only true for OS(DARWIN) since vm_protect is Mach API.
     21
     22        3. Rename disableDisablingPrimitiveGigacageIfShouldBeEnabled() to
     23           forbidDisablingPrimitiveGigacage() because "disablingDisabling" is a tongue
     24           twister.
     25
     26           Also, we don't want to make it conditional on "IfShouldBeEnabled".  We want
     27           forbidDisablingPrimitiveGigacage() to be irreversible.  It is up to the client
     28           to ensure that the Gigacage is already initialized (if possible) before
     29           invoking forbidDisablingPrimitiveGigacage().  Conceptually, the forbidding
     30           isn't about guaranteeing that the Gigacage is enabled.  It only takes away the
     31           option to disable it.
     32
     33           That said, forbidDisablingPrimitiveGigacage() is only invoked by clients that
     34           care about keeping the Gigacage enabled.  So, it does a sanity check (with an
     35           assertion) that if !GIGACAGE_ALLOCATION_CAN_FAIL, then the Gigacage should be
     36           have been initialized and enabled before invoking it.
     37
     38           We also make sure that forbidDisablingPrimitiveGigacage() calls
     39           permanentlyFreezeGigacageConfig() unconditionally.  It is safe to call it more
     40           than once.  This guarantees that the Config is permanently frozen after this,
     41           even if a bug should inadvertantly set the
     42           g_gigacageConfig.disablingPrimitiveGigacageIsForbidden flag before
     43           forbidDisablingPrimitiveGigacage() is invoked.
     44
     45        4. Assert that ensureGigacage() is only called once.
     46
     47        5. Assert that shouldBeEnabled() is only called once.
     48           Also moved its cached result into the Config so that it can be frozen.
     49
     50        * bmalloc/Gigacage.cpp:
     51        (Gigacage::bmalloc::freezeGigacageConfig):
     52        (Gigacage::bmalloc::unfreezeGigacageConfig):
     53        (Gigacage::bmalloc::permanentlyFreezeGigacageConfig):
     54        (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope):
     55        (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope):
     56        (Gigacage::ensureGigacage):
     57        (Gigacage::disablePrimitiveGigacage):
     58        (Gigacage::verifyGigacageIsEnabled):
     59        (Gigacage::forbidDisablingPrimitiveGigacage):
     60        (Gigacage::isDisablingPrimitiveGigacageForbidden):
     61        (Gigacage::shouldBeEnabled):
     62        (Gigacage::bmalloc::protectGigacageBasePtrs): Deleted.
     63        (Gigacage::bmalloc::unprotectGigacageBasePtrs): Deleted.
     64        (Gigacage::bmalloc::UnprotectGigacageBasePtrsScope::UnprotectGigacageBasePtrsScope): Deleted.
     65        (Gigacage::bmalloc::UnprotectGigacageBasePtrsScope::~UnprotectGigacageBasePtrsScope): Deleted.
     66        (Gigacage::primitiveGigacageDisabled): Deleted.
     67        (Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled): Deleted.
     68        (Gigacage::isDisablingPrimitiveGigacageDisabled): Deleted.
     69        * bmalloc/Gigacage.h:
     70        (Gigacage::isPrimitiveGigacagePermanentlyEnabled):
     71        (Gigacage::canPrimitiveGigacageBeDisabled):
     72        (Gigacage::forbidDisablingPrimitiveGigacage):
     73        (Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled): Deleted.
     74
    1752019-09-06  Mark Lam  <mark.lam@apple.com>
    276
  • trunk/Source/bmalloc/bmalloc/Gigacage.cpp

    r249556 r249608  
    3636#include <mutex>
    3737
     38#if BOS(DARWIN)
     39#include <mach/mach.h>
     40#endif
     41
    3842#if GIGACAGE_ENABLED
    3943
     
    8286namespace {
    8387
    84 bool s_isDisablingPrimitiveGigacageDisabled;
    85 
    86 void protectGigacageBasePtrs()
    87 {
    88     // We might only get page size alignment, but that's also the minimum we need.
    89     RELEASE_BASSERT(!(reinterpret_cast<size_t>(&g_gigacageConfig) & (vmPageSize() - 1)));
    90     mprotect(&g_gigacageConfig, configSizeToProtect, PROT_READ);
    91 }
    92 
    93 void unprotectGigacageBasePtrs()
    94 {
    95     mprotect(&g_gigacageConfig, configSizeToProtect, PROT_READ | PROT_WRITE);
    96 }
    97 
    98 class UnprotectGigacageBasePtrsScope {
     88#if BOS(DARWIN)
     89enum {
     90    AllowPermissionChangesAfterThis = false,
     91    DisallowPermissionChangesAfterThis = true
     92};
     93#endif
     94
     95static void freezeGigacageConfig()
     96{
     97    int result;
     98#if BOS(DARWIN)
     99    result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(&g_gigacageConfig), configSizeToProtect, AllowPermissionChangesAfterThis, VM_PROT_READ);
     100#else
     101    result = mprotect(&g_gigacageConfig, configSizeToProtect, PROT_READ);
     102#endif
     103    RELEASE_BASSERT(!result);
     104}
     105
     106static void unfreezeGigacageConfig()
     107{
     108    RELEASE_BASSERT(!g_gigacageConfig.isPermanentlyFrozen);
     109    int result;
     110#if BOS(DARWIN)
     111    result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(&g_gigacageConfig), configSizeToProtect, AllowPermissionChangesAfterThis, VM_PROT_READ | VM_PROT_WRITE);
     112#else
     113    result = mprotect(&g_gigacageConfig, configSizeToProtect, PROT_READ | PROT_WRITE);
     114#endif
     115    RELEASE_BASSERT(!result);
     116}
     117
     118static void permanentlyFreezeGigacageConfig()
     119{
     120    if (!g_gigacageConfig.isPermanentlyFrozen) {
     121        unfreezeGigacageConfig();
     122        g_gigacageConfig.isPermanentlyFrozen = true;
     123    }
     124
     125    // There's no going back now!
     126    int result;
     127#if BOS(DARWIN)
     128    result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(&g_gigacageConfig), configSizeToProtect, DisallowPermissionChangesAfterThis, VM_PROT_READ);
     129#else
     130    result = mprotect(&g_gigacageConfig, configSizeToProtect, PROT_READ);
     131#endif
     132    RELEASE_BASSERT(!result);
     133}
     134
     135class UnfreezeGigacageConfigScope {
    99136public:
    100     UnprotectGigacageBasePtrsScope()
     137    UnfreezeGigacageConfigScope()
    101138    {
    102         unprotectGigacageBasePtrs();
    103     }
    104    
    105     ~UnprotectGigacageBasePtrsScope()
     139        unfreezeGigacageConfig();
     140    }
     141   
     142    ~UnfreezeGigacageConfigScope()
    106143    {
    107         protectGigacageBasePtrs();
     144        freezeGigacageConfig();
    108145    }
    109146};
     
    130167        onceFlag,
    131168        [] {
     169            RELEASE_BASSERT(!g_gigacageConfig.ensureGigacageHasBeenCalled);
     170            g_gigacageConfig.ensureGigacageHasBeenCalled = true;
     171
    132172            if (!shouldBeEnabled())
    133173                return;
    134174           
     175            // We might only get page size alignment, but that's also the minimum
     176            // alignment we need for freezing the Config.
     177            RELEASE_BASSERT(!(reinterpret_cast<size_t>(&g_gigacageConfig) & (vmPageSize() - 1)));
     178
    135179            Kind shuffledKinds[NumberOfKinds];
    136180            for (unsigned i = 0; i < NumberOfKinds; ++i)
     
    192236            vmDeallocatePhysicalPages(base, totalSize);
    193237            g_gigacageConfig.isEnabled = true;
    194             protectGigacageBasePtrs();
     238            freezeGigacageConfig();
    195239        });
    196240}
     
    198242void disablePrimitiveGigacage()
    199243{
     244    if (g_gigacageConfig.disablingPrimitiveGigacageIsForbidden)
     245        fprintf(stderr, "FATAL: Disabling Primitive gigacage is forbidden, but we don't want that in this process.\n");
     246
     247    RELEASE_BASSERT(!g_gigacageConfig.disablingPrimitiveGigacageIsForbidden);
     248    RELEASE_BASSERT(!g_gigacageConfig.isPermanentlyFrozen);
     249
    200250    ensureGigacage();
    201251    if (!g_gigacageConfig.basePtrs[Primitive]) {
     
    210260        callback.function(callback.argument);
    211261    callbacks.callbacks.shrink(0);
    212     UnprotectGigacageBasePtrsScope unprotectScope;
     262    UnfreezeGigacageConfigScope unfreezeScope;
    213263    g_gigacageConfig.basePtrs[Primitive] = nullptr;
    214264}
     
    242292}
    243293
    244 static void primitiveGigacageDisabled(void*)
    245 {
    246     if (GIGACAGE_ALLOCATION_CAN_FAIL && !isEnabled())
    247         return;
    248 
    249     static bool s_false;
    250     fprintf(stderr, "FATAL: Primitive gigacage disabled, but we don't want that in this process.\n");
    251     if (!s_false)
    252         BCRASH();
    253 }
    254 
    255 void disableDisablingPrimitiveGigacageIfShouldBeEnabled()
    256 {
    257     if (shouldBeEnabled()) {
    258         addPrimitiveDisableCallback(primitiveGigacageDisabled, nullptr);
    259         s_isDisablingPrimitiveGigacageDisabled = true;
    260     }
    261 }
    262 
    263 bool isDisablingPrimitiveGigacageDisabled()
    264 {
    265     return s_isDisablingPrimitiveGigacageDisabled;
     294static bool verifyGigacageIsEnabled()
     295{
     296    bool isEnabled = g_gigacageConfig.isEnabled;
     297    for (size_t i = 0; i < NumberOfKinds; ++i)
     298        isEnabled = isEnabled && g_gigacageConfig.basePtrs[i];
     299    return isEnabled;
     300}
     301
     302void forbidDisablingPrimitiveGigacage()
     303{
     304    RELEASE_BASSERT(GIGACAGE_ALLOCATION_CAN_FAIL || verifyGigacageIsEnabled());
     305    if (!g_gigacageConfig.disablingPrimitiveGigacageIsForbidden) {
     306        unfreezeGigacageConfig();
     307        g_gigacageConfig.disablingPrimitiveGigacageIsForbidden = true;
     308    }
     309    permanentlyFreezeGigacageConfig();
     310    RELEASE_BASSERT(isDisablingPrimitiveGigacageForbidden());
     311}
     312
     313BNO_INLINE bool isDisablingPrimitiveGigacageForbidden()
     314{
     315    return g_gigacageConfig.disablingPrimitiveGigacageIsForbidden;
    266316}
    267317
    268318bool shouldBeEnabled()
    269319{
    270     static bool cached = false;
    271320    static std::once_flag onceFlag;
    272321    std::call_once(
    273322        onceFlag,
    274323        [] {
     324            RELEASE_BASSERT(!g_gigacageConfig.shouldBeEnabledHasBeenCalled);
     325            g_gigacageConfig.shouldBeEnabledHasBeenCalled = true;
     326
    275327            bool debugHeapEnabled = Environment::get()->isDebugHeapEnabled();
    276328            if (debugHeapEnabled)
     
    288340            }
    289341           
    290             cached = true;
     342            g_gigacageConfig.shouldBeEnabled = true;
    291343        });
    292     return cached;
     344    return g_gigacageConfig.shouldBeEnabled;
    293345}
    294346
     
    296348
    297349#endif // GIGACAGE_ENABLED
    298 
    299 
  • trunk/Source/bmalloc/bmalloc/Gigacage.h

    r249556 r249608  
    114114    union {
    115115        struct {
     116            // All the fields in this struct should be chosen such that their
     117            // initial value is 0 / null / falsy because Config is instantiated
     118            // as a global singleton.
     119
    116120            bool isEnabled;
     121            bool isPermanentlyFrozen;
     122            bool disablingPrimitiveGigacageIsForbidden;
     123            bool shouldBeEnabled;
     124
     125            // We would like to just put the std::once_flag for these functions
     126            // here, but we can't because std::once_flag has a implicitly-deleted
     127            // default constructor. So, we use a boolean instead.
     128            bool shouldBeEnabledHasBeenCalled;
     129            bool ensureGigacageHasBeenCalled;
     130
    117131            void* basePtrs[NumberOfKinds];
    118132        };
     
    139153BEXPORT void removePrimitiveDisableCallback(void (*)(void*), void*);
    140154
    141 BEXPORT void disableDisablingPrimitiveGigacageIfShouldBeEnabled();
    142 
    143 BEXPORT bool isDisablingPrimitiveGigacageDisabled();
    144 inline bool isPrimitiveGigacagePermanentlyEnabled() { return isDisablingPrimitiveGigacageDisabled(); }
    145 inline bool canPrimitiveGigacageBeDisabled() { return !isDisablingPrimitiveGigacageDisabled(); }
     155BEXPORT void forbidDisablingPrimitiveGigacage();
     156
     157BEXPORT bool isDisablingPrimitiveGigacageForbidden();
     158inline bool isPrimitiveGigacagePermanentlyEnabled() { return isDisablingPrimitiveGigacageForbidden(); }
     159inline bool canPrimitiveGigacageBeDisabled() { return !isDisablingPrimitiveGigacageForbidden(); }
    146160
    147161BINLINE void* basePtr(Kind kind)
     
    234248template<typename T> BINLINE T* caged(Kind, T* ptr) { return ptr; }
    235249template<typename T> BINLINE T* cagedMayBeNull(Kind, T* ptr) { return ptr; }
    236 BINLINE void disableDisablingPrimitiveGigacageIfShouldBeEnabled() { }
     250BINLINE void forbidDisablingPrimitiveGigacage() { }
    237251BINLINE bool canPrimitiveGigacageBeDisabled() { return false; }
    238252BINLINE void disablePrimitiveGigacage() { }
Note: See TracChangeset for help on using the changeset viewer.