Home > Articles > Home & Office Computing > Mac OS X

This chapter is from the book

For the More Curious: Blocks Internals

Blocks and __block variables are implemented by a combination of structures and functions. These are generated by the compiler and maintained by a runtime environment. Knowing how things work under the hood is useful for understanding the details of memory management and debugging.

Implementation

The compiler interprets the new, block-specific syntax and generates data to interface with the runtime and code that relies on functions provided by the runtime. The blocks runtime enables the use of blocks while the application is actually running.

The specific compiler is irrelevant to our discussion. The most visible difference between gcc and clang is in the names generated for the private structures and functions created by the compiler to support blocks and __block variables.

Those private structures and functions make up the heart of the blocks implementation.

Block literals

Each block literal definition triggers the compiler to generate two structures and at least one function. The two structures describe the block and its runtime information. The function contains the executable code of the block.

The two structures are the block literal (also known as the "block holder") and the block descriptor.

A block descriptor looks like:

static const struct block_descriptor_NAME {
    unsigned long reserved;
    unsigned long literal_size;

    /* helper functions - present only if needed */
    void (*copy_helper)(void *dst, void *src);
    void (*dispose_helper)(void *src);
};

The reserved field is currently unused. The literal_size field is set to the size of the corresponding block literal. The two helper function pointers are only present if needed. They are needed when the block references an Objective-C or C++ object or a __block variable. When helper functions are necessary, the compiler generates them in addition to the function implementing the body of the block literal.

A block literal looks like:

struct block_literal_NAME {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(void *literal, ...);
    struct block_descriptor_NAME *descriptor;
    /* referenced captured variables follow */
};

The isa pointer is what makes a block into an Objective-C object. Even when not using Objective-C, the isa pointer is still used by the blocks runtime to indicate what kind of block it is dealing with.

The isa field will point to:

_NSConcreteStackBlock

when the block is on the stack.

_NSConcreteGlobalBlock

when the block is in global storage.

_NSConcreteMallocBlock

when the block is on the heap.

_NSConcreteAutoBlock

when the block is in collectable memory. This class is used when running under the garbage collector and a stack block not referencing a C++ object is copied to the heap.

_NSConcreteFinalizingBlock

when the block is in collectable memory and must have a finalizer run when it is collected. This class is used when running under the garbage collector and a stack block referencing a C++ object is copied to the heap, because the runtime must ensure that the C++ object's destructor is called when the block is collected.

All of these block classes are subclasses of _NSAbstractBlock. The abstract class provides implementations for the memory-related methods used by blocks. The various concrete subclasses exist solely to indicate information about where the block is stored.

The flags field provides further information about the block:

enum {
    BLOCK_REFCOUNT_MASK    = (0xFFFF),
    BLOCK_NEEDS_FREE       = (1 << 24),
    BLOCK_HAS_COPY_DISPOSE = (1 << 25),
    BLOCK_HAS_CXX_OBJ      = (1 << 26),
    BLOCK_IS_GC            = (1 << 27),
    BLOCK_IS_GLOBAL        = (1 << 28),
    BLOCK_HAS_DESCRIPTOR   = (1 << 29),
};

BLOCK_REFCOUNT_MASK, BLOCK_NEEDS_FREE, and BLOCK_IS_GC are set as appropriate by the runtime when a block is copied.

BLOCK_IS_GLOBAL is set at compile time for blocks in global storage. Copying and releasing such a block has no effect, as the block is always present in the application's memory. The compiler might opt to hoist a stack-local block into static memory and set the BLOCK_IS_GLOBAL flag if it has no references to any stack-local (which includes __block) variables.

BLOCK_HAS_DESCRIPTOR is always set. It was added to distinguish the version of the blocks implementation that was eventually released with Snow Leopard from an earlier implementation.

Every block invoke function takes a pointer to the calling block literal as its first argument. This provides the function with access to the block's captured variables. This is functionally identical to the this pointer passed as the first argument to C++ member functions, which the member function uses to access the member variables, and the self pointer supplied as the first argument to Objective-C instance methods, which the method uses to access the instance variables. As in C++, the return value and remaining arguments of the block invoke function are those declared by the programmer. (Objective-C adds one more implicit argument between self and the programmer-declared arguments, _cmd, which is set to the method's selector.)

Aside from the obvious referenced captured variables, blocks also are considered to have referenced all variables referenced by any blocks nested within them. Consider this brief example:

int x = 0;
int y = 1;
int (^b)(void) = ^{
    int (^c)(void) = ^{
        return y;
    };
    return x + c();
}

Here, the block assigned to b is considered to have referenced both x and y.

To see how block literals, block descriptors, and block invoke functions come together, consider this code:

void f(void) {
    int x = 0;
    int (^b)(void) = ^{ return x + 1; };
    int y = b();
}

The compiler would turn that code into something like this:

typedef void (*generic_invoke_funcptr)(void *, ...);
struct __block_literal {
    void *isa;
    int flags;
    int reserved;
    generic_invoke_funcptr invoke;
    struct __block_descriptor_tmp *descriptor;
    const int captured_x;
};

static const struct __block_descriptor_tmp {
    unsigned long reserved;
    unsigned long literal_size;
    /* no copy/dispose helpers needed */
} __block_descriptor_tmp = {
    0UL, sizeof(struct __block_literal)
};

// ^int (void) { return x + 1; }
int __f_block_invoke_(struct __block_literal *bp) {
    return bp->captured_x + 1;
}
typedef int (*iv_funcptr)(struct __block_literal *);

void f(void) {
    int x = 0;
    // int (^b)(void) = ^{ return x + 1 };
    struct __block_literal __b = {
        .isa = &_NSConcreteStackBlock,
        .flags = BLOCK_HAS_DESCRIPTOR,
        .reserved = 0,
        .invoke = (generic_invoke_funcptr)__f_block_invoke_,
        .descriptor = &__block_descriptor_tmp,
        .captured_x = x
    };
    struct __block_literal *b = &__b;
    int y = (*(iv_funcptr)(b->invoke))(b);
}

Notice that the block variable is really a pointer to a structure created on the stack. It can be helpful to keep this in mind when thinking about when a block literal must be copied or not.

__block variables

Like block literals, __block variables can move from the stack to the heap and their variable data can require memory management, such as when it is an Objective-C object. Consequently, __block variables are also compiled into a struct and, if necessary, ancillary functions.

In order that all manipulations of the __block variable deal with the current location of the variable, all access is mediated by a forwarding pointer. When a __block variable is copied from the stack to the heap, the forwarding pointers of both the on-stack and in-heap structures are updated to point to the in-heap structure.

Because all __block variable access is by reference, the names of the structure and functions associated with __block variables embed "byref."

The byref structure looks like:

struct Block_byref {
    void *isa;
    struct Block_byref *forwarding;
    int flags;
    int size;

    /* helper functions - present only if needed */
    void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src);
    void (*byref_destroy)(struct Block_byref *);

    /* actual variable data follows */
}

The isa field is always NULL to start with. When a __weak-qualified __block variable is copied, the field is set to &NSConcreteWeakBlockVariable.

The forwarding pointer always points to the start of the authoritative byref header. To begin with, this will always be the address of the containing byref structure itself.

The flags field is used to indicate whether copy and dispose helper functions are present. If they are not, it will be initialized to 0; otherwise, it will be initialized to BLOCK_HAS_COPY_DISPOSE. As with block literals, when the structure is copied at runtime, the flags field will be updated with memory management information. If it is copied into scanned memory, BLOCK_IS_GC will be set. Otherwise, BLOCK_NEEDS_FREE will be set and the bottom two bytes used to store a reference count.

The size is set to the size of the particular Block_byref structure.

Helper functions will be synthesized by the compiler if the byref variable is a block reference, an Objective-C object, or a C++ object. If they are present, flags will include BLOCK_HAS_COPY_DISPOSE. They will be invoked when copying and when releasing a block that references a __block variable.

When a block captures a __block variable, it holds onto the byref structure's forwarding pointer and uses that to interact with the variable. The block will then need copy and dispose helpers to handle copying and disposing of the captured __block variable.

As an example, we will return to the function f. We will change it slightly by moving the referenced variable x from auto storage to __block storage:

void f(void) {
    __block int x = 0;
    int (^b)(void) = ^{ return x + 1; };
    int y = b();
}

In response, the compiler will generate something like the following code (the changes wrought by adding __block have been emphasized):

   // __block int x
   struct __byref_x {
   /* header */
   void *isa;
   struct __byref_x *forwarding;
   int flags;
   int size;
   /* no helpers needed */
   int x;
   };


typedef void (*generic_invoke_funcptr)(void *, ...);
struct __block_literal {
    void *isa;
    int flags;
    int reserved;
    generic_invoke_funcptr invoke;
    struct __block_descriptor_tmp *descriptor;

    struct __byref_x *captured_x;

};


void __copy_helper_block_(struct __block_literal *dst,
                             struct __block_literal *src);
void __destroy_helper_block_(struct __block_literal *bp);


typedef void (*generic_copy_funcptr)(void *, void *);
typedef void (*generic_dispose_funcptr)(void *);
static const struct __block_descriptor_tmp {
    unsigned long reserved;
    unsigned long literal_size;

    /* helpers to copy __block reference captured_x */
    generic_copy_funcptr copy;
    generic_dispose_funcptr dispose;

} __block_descriptor_tmp = {
    0UL, sizeof(struct __block_literal),

   (generic_copy_funcptr)__copy_helper_block_,
   (generic_dispose_funcptr)__destroy_helper_block_
};

// ^int (void) { return x + 1; }
int __f_block_invoke_(struct __block_literal *bp) {
    return bp->captured_x->forwarding->x + 1;
}
typedef int (*iv_funcptr)(struct __block_literal *);


void f(void) {

    // __block int x = 0;
    struct __byref_x x = {
        .isa = NULL,
        .forwarding = &x,
        .flags = 0,
        .size = sizeof(x),
        .x = 0
    };

    // int (^b)(void) = ^{ return x + 1 };
    struct __block_literal __b = {
        .isa = &_NSConcreteStackBlock,
        .flags = BLOCK_HAS_DESCRIPTOR,
        .reserved = 0,
        .invoke = (generic_invoke_funcptr)__f_block_invoke_,
        .descriptor = &__block_descriptor_tmp,

        .captured_x = x.forwarding

    };
    struct __block_literal *b = &__b;
    int y = (*(iv_funcptr)(b->invoke))(b);


    // Clean up before leaving scope of x.
    _Block_object_dispose(x.forwarding, BLOCK_FIELD_IS_BYREF);
}


void __copy_helper_block_(struct __block_literal *dst,
                          struct __block_literal *src) {
  _Block_object_assign(&dst->captured_x, src->captured_x,
                       BLOCK_FIELD_IS_BYREF);
}

void __destroy_helper_block_(struct __block_literal *bp) {
  _Block_object_dispose(bp->captured_x, BLOCK_FIELD_IS_BYREF);
}

Of particular note here is the call to _Block_object_dispose() at the end of f(). This is because, when garbage collection is not being used, the runtime must adjust the reference count of the __block variable whenever it goes out of scope. When all references have been eliminated, the runtime releases any allocated storage.

The functions used by the helper functions, _Block_object_assign() and _Block_object_dispose(), are provided by the blocks runtime for use by the compiler. Their behavior is heavily determined by the final argument, const int flags, which provides information on the type of the object being assigned or disposed of. The possible values of this field are:

enum {
    BLOCK_FIELD_IS_OBJECT   =  3,
    BLOCK_FIELD_IS_BLOCK    =  7,
    BLOCK_FIELD_IS_BYREF    =  8,
    BLOCK_FIELD_IS_WEAK     = 16,
    BLOCK_BYREF_CALLER      = 128
};

The BLOCK_BYREF_CALLER flag is used to signal to the functions that they are being called by a byref structure's byref_keep or byref_destroy function. It is only ever set by such functions.

The other flags are set as appropriate for the type of the object being assigned or disposed. Notice that a block field is also an object, since BLOCK_FIELD_IS_BLOCK & BLOCK_FIELD_IS_OBJECT results in BLOCK_FIELD_IS_OBJECT. Where distinguishing between an object and a block object is important, the runtime functions are careful to test whether the block flag is set before testing whether the object flag is set.

Debugging

Debugging blocks can be tricky as the debugging environment straddles the line between the abstraction and the implementation. gcc provides far better debugging information than clang, but this might change in the future.

gdb comes with only one block-specific command: invoke-block, which you can unambiguously abbreviate to inv. Its arguments are a block reference or the address of a block literal structure followed by the declared arguments to the block function. The arguments are separated by spaces, so arguments with spaces must be enclosed in double quotation marks. Double quotation marks within quoted arguments must be escaped with a backslash. The only time you are likely to encounter this is in passing a string argument to a block; the resulting command would look like:

inv string_block "\"string argument\""

gcc and clang differ significantly in the debugging information they supply for blocks.

gcc's debugging information

gcc embeds a goodly amount of debugging information about blocks. The print command (p for short) picks up that block references are pointers, and you can use ptype to print the compiler-generated type of a block:

(gdb) p local_block
$1 = (struct __block_literal_2 *) 0xbffff854
(gdb) ptype local_block
type = struct __block_literal_2 {
    void *__isa;
    int __flags;
    int __reserved;
    void *__FuncPtr;
    struct __block_descriptor_withcopydispose *__descriptor;
    const char *enc_vbv;
    struct __Block_byref_1_i *i;
} *
(gdb) ptype local_block->__descriptor
type = struct __block_descriptor_withcopydispose {
    long unsigned int reserved;
    long unsigned int Size;
    void *CopyFuncPtr;
    void *DestroyFuncPtr;
} *

You can also use the Objective-C command print-object (po for short) to get a different view on the block:

(gdb) po local_block
<__NSStackBlock__: 0xbffff854>

Getting information on local variables within a block will show that gcc adds the __func__ variable, which is set to the name of the function. If you get information on the function arguments, you will see the implicit block literal pointer argument:

(gdb) i args
.block_descriptor = (struct __block_literal_2 *) 0xbffff854

The debugging information generated by gcc pretends that __block variables are identical to their auto counterparts, so that if you have a variable __block int i, you will find that printing the i and its size will behave the same as printing a variable int i.

clang's debugging information

clang, unfortunately, provides no debugging information for block references. The debugger finds no type information for block references. It also has no way to look up the block implementation function for a block so that invoke-block always fails.

You can still set breakpoints in blocks by setting them at a line in a file or at the invocation function, if you can determine its name, but you will find that clang pretends that block implementation functions have the same arguments as the block literal, so you cannot readily gain access to the implicit block literal pointer argument. Interestingly, clang does not report any __func__ local variable; it generates a warning if you use it from a block literal, but you will find that the variable is in fact present, regardless of what the debugging information says.

clang also emits no debugging information for __block variables. They do not appear in the list of local variables, and any attempt to reference them results in a message like:

No symbol "i" in current context.

While you could make headway by using what you know of the blocks implementation to cadge the desired information out of a program compiled using clang, until these issues are fixed, you would do well to use gcc when compiling an application using blocks where you plan to rely on the debugging information in future.

Dumping runtime information

Apple's blocks runtime includes a couple functions for dumping information about a block reference and a __block variable.

These functions are:

const char *_Block_dump(const void *block);
const char *_Block_byref_dump(struct Block_byref *src);

You can call these from gdb to dump information about a block or __block variable. If you have the following declarations:

__block int i = 23;
void (^local_block)(void) = ^{ /*...*/ };

then you can dump information about them as follows:

(gdb) call (void)printf((const char *)_Block_dump(local_block))
^0xbffff854 (new layout) =
isa: stack Block
flags: HASDESCRIPTOR HASHELP
refcount: 0
invoke: 0x1e50
descriptor: 0x20bc
descriptor->reserved: 0
descriptor->size: 28
descriptor->copy helper: 0x1e28
descriptor->dispose helper: 0x1e0a

(gdb) set $addr = (char *)&i - 2*sizeof(int) - 2*sizeof(void *)
(gdb) call (void)printf((const char *)_Block_byref_dump($addr))
byref data block 0xbffff870 contents:
  forwarding: 0xbffff870
  flags: 0x0
  size: 20

Note that, though the debugging information supplied by gcc pretends that the __block variable i is simply an int variable, the address of the variable is in fact its address within the byref structure. Since we know the layout of the structure, we can calculate the address of the start of the structure and pass that to _Block_byref_dump().

You can wrap these calls in user-defined commands. Adding the following definitions to your .gdbinit file will make them available whenever you run gdb:

define dump-block-literal
    printf "%s", (const char *)_Block_dump($arg0)
end

document dump-block-literal
    Dumps runtime information about the supplied block reference.
    Argument is the name or address of a block reference.
end


define dump-block-byref
    set $_dbb_addr = (char *)&$arg0 - 2*sizeof(int) - 2*sizeof(void *)
    printf "%s", (const char *)_Block_byref_dump($_dbb_addr)
end

document dump-block-byref
    Dumps runtime information about the supplied __block variable.
    Argument is a pointer to the variable embedded in a block byref structure.
end

With these commands defined, dumping that information is as simple as:

(gdb) dump-block-literal local_block
^0xbffff854 (new layout) =
isa: stack Block
flags: HASDESCRIPTOR HASHELP
refcount: 0
invoke: 0x1e50
descriptor: 0x20bc
descriptor->reserved: 0
descriptor->size: 28
descriptor->copy helper: 0x1e28
descriptor->dispose helper: 0x1e0a
(gdb) dump-block-byref i
byref data block 0xbffff870 contents:
  forwarding: 0xbffff870
  flags: 0x0
  size: 20

Evolving the implementation

This chapter has described the blocks runtime as released with Mac OS X 10.6 (Snow Leopard). The blocks runtime is unlikely to make any changes that would break code compiled to that interface, but it will not stop evolving.

There are several extension points built into the current runtime. The various flags fields can be carefully extended; reserved fields can be repurposed; and new fields can be tacked on at the ends of the various structures.

One minor extension that might see release is the addition of a signature field at the end of the block descriptor structure. This field would contain a pointer to the Objective-C type encoding of the block invoke function.

(For those curious, blocks themselves are encoded by the @encode directive as @?; this parallels the function pointer encoding of ^?, which literally reads as "pointer to unknown type.")

To indicate that this field is present, the BLOCK_HAS_DESCRIPTOR flag would no longer be set, and a new flag, BLOCK_HAS_SIGNATURE = (1 << 30), would be set in all blocks compiled for the new runtime.

With the ability to test for BLOCK_HAS_SIGNATURE to check for a block compiled against a newer version of the runtime, the way is opened for other changes, including repurposing BLOCK_HAS_DESCRIPTOR to signal that a block returns a structure large enough to require special handling on some architectures. The flag could be renamed BLOCK_USE_STRET. This is similar to the way that objc_msgSend_stret() is used by the Objective-C runtime instead of objc_msgSend() in the same situation.

A more significant change would be to add the signature of the variables captured by a block. This would allow the runtime to eliminate helper functions in favor of using the type information now encoded along with the block to itself do the right thing for all captured variables when a block is copied or disposed.

Compiler-generated names

Both gcc and clang automatically generate names for the structures and functions that make up blocks and __block variables. Sometimes during debugging, it would be useful to be able to guess the names generated in implementing a given block or __block variable.

Unfortunately, outside of toy examples, this is generally not possible without reference to a disassembly of the code. Both compilers disambiguate the names of the structures and helper functions they generate by appending numbers to the end of the same string. Thus, you can judge the type of support structure or helper you are looking at, but you cannot readily trace it back to the block or __block variable that caused its generation.

Fortunately, the outlook is not so bleak when it comes to block invoke functions. Block invoke functions not defined at global scope embed the name of the outermost enclosing function. The first block in a function f() will be named __f_block_invoke_1 if generated by gcc and __f_block_invoke_ if generated by clang. The numeric suffix is incremented prior to generating the name of the block invoke function of each subsequent block encountered within the function. (clang starts by appending the number 1 and increments it like gcc thereafter.) Objective-C method names will be embedded just as C function names, leading to block invoke function names like __-[Foo init]_block_invoke_1. C++ member functions are neither qualified nor mangled for embedding, so a block defined within the member function Foo::Bar() will cause the compiler to generate a block invoke function named __Bar_block_invoke_ (append a 1 if the compiler is gcc).

The block invoke functions of blocks defined at global scope are harder to track down, since they have no enclosing function to anchor them. gcc names such functions starting with __block_global_1. clang uses the same name scheme as for blocks defined within a function, only it substitutes global as the function name. Consequently, the first block defined at global scope that clang encounters is named __global_block_invoke_, and the second, __global_block_invoke_1.

One surprising result of the naming conventions for blocks at global scope is that when several source files are compiled into a single executable, each one can have its own __global_block_invoke_ function. The resulting executable will have several functions with the identical name distinguished by their being at different addresses.

Whenever possible, specify breakpoints in block functions using the file and line number rather than the name. The name generation scheme could change in future and does not guarantee uniqueness within a linked executable, only within a compilation unit.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020