Last update: 29 April,2000
2000 #003r2 _____________________________________________________________________________ Topic: pthreads stack handling Relevant Sections: pthread_ Spec: XSH5 Resolution Request: ------------------- POSIX 1003.1c included an optional feature known as the "stackaddr" attribute, manipulated using the pthread_attr_setstackaddr() and pthread_attr_getstackaddr() functions. This optional features was designed to allow an application to create and manage its own stacks. PROBLEM STATEMENT: There are some problems with the "stackaddr" attribute, stemming from the fact that the standard does not provide any way to specify the size of the application-managed stack. 1. The implementation cannot know the size without guessing, or utilizing some non-standard mechanism. 2. The standard does not specify, or even suggest, the relationship between the specified address and the actual base of the thread's stack. There various possibilities, depending on whether the machine modifies a stack pointer before or after storing data, and whether it increases or decreases the stack pointer. (There are more than the obvious four combinations because on Intel's IA-64 architecture each thread has two independent stacks, one of which grows UP while the other grows DOWN.) An implementation can only make one "guess" about the stack's size that's remotely supported by the standard: that the stack is precisely PTHREAD_STACK_MIN bytes. This, however, is not useful because, by definition, that is a "minimal" size, not even a "typical" size. There's little value to an application in being able to "manage its own stacks" if it can do so only for stacks of the architecturally minimum size. The only suggestion provided by the standard for a means to specify the size of a "stackaddr" stack is to presume a connection between the "stackaddr" and "stacksize" attributes. No such connection, however, is specified, or even explicitly allowed, by the standard. Therefore, any application depending on such a connection is non-portable. To require such a connection now would break existing applications, where the value of "stacksize" that happens to be in an attributes object could suddenly become an actual limit. Furthermore, there's little value to improving the situation unless we define "stackaddr" in a way that would become portable, such as specifying that it be the low address of the stack. Such a change would also break existing code on real implementations. (For example, Tru64 UNIX, where "stackaddr" must specify the address immediately following the stack buffer because the stack grows down and the pointer is decreased before storing data.) PROPOSED SOLUTION: The "stackaddr" attribute should be marked "obsolete", and should be replaced by an attribute that's clear, useful, and can be used portably, such as the proposed "stack" attribute. An application-managed stack is specified using the low memory address (e.g., the address returned by malloc, or mmap), and a size. The implementation can position the thread's initial stack pointer(s) where necessary and appropriate within that region, without guessing, and without additional assistance from the application. The "stack" attribute is intended to be MINIMAL, not COMPREHENSIVE. For example, it has frequently been assumed that applications can provide stack overflow protection with a protected page (or pages) outside the described area. However, no fully portable application can do this, because it would still need to know at which end of the stack the protected page should go. While it could place protected pages at both ends, an implementation on Intel's IA-64 is likely to create two separate stacks that grow towards the center of the provided region. It would be possible to extend the stack attribute interface, either by adding a parameter or by specifying a connection with the "guardsize" attribute, to cause the implementation to provide appropriate guard page(s) for the application stack. (I'd prefer to avoid such a connection, because experience has shown, as with policy and priority, and expecially inheritsched, that this causes programmer confusion and unnecessary support calls.) I am not proposing either extension, but I would not object to adding a "guardsize" parameter to the "stack" attribute functions. Resolution Response ------------------- Two new functions will be added to a future revision of the specification. A new manual page is attached. This is an XSI extension. NAME pthread_attr_getstack, pthread_attr_setstack - get and set stack attribute SYNOPSIS #include <pthread.h> int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize); int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); DESCRIPTION The functions pthread_attr_getstack() and pthread_attr_setstack(), respectively, shall get and set the thread creation stack attribute in the attr object. The stack attribute specifies the area of storage to be used for the created thread's stack. The base (lowest addressable byte) of the storage is stackaddr, and the size of the storage is stacksize bytes. The stacksize shall be at least PTHREAD_STACK_MIN. The stackaddr shall be aligned appropriately to be used as a stack; for example, pthread_attr_setstack may fail with EINVAL if (stackaddr & 0x7) is not 0. All pages within the stack described by stackaddr and stacksize shall be both readable and writeable by the thread. RETURN VALUE Upon successful completion, pthread_attr_getstack() and pthread_attr_setstack() shall return a value of 0; otherwise, an error number shall be returned to indicate the error. The pthread_attr_getstack() function shall store the stack attribute values in stackaddr and stacksize if successful. ERRORS The pthread_attr_setstack() function shall fail if: [EINVAL] The value of stacksize is less than PTHREAD_STACK_MIN or exceeds a system-imposed limit. The pthread_attr_setstack() function may fail if: [EINVAL] The value of stackaddr does not have proper alignment to be used as a stack, or if (stackaddr + stacksize) lacks proper alignment. [EACCES] The stack page(s) describe by stackaddr and stacksize are not both readable and writeable by the thread. These functions shall not return an error code of [EINTR]. EXAMPLES None. APPLICATION USAGE These functions are appropriate for use by applications in an environment where the stack for a thread must be placed in some particular region of memory. While it might seem that an application could detect stack overflow by providing a protected page outside the specified stack region, this cannot be done portably. Implementations are free to place the thread's initial stack pointer anywhere within the specified region to accomodate the machine's stack pointer behavior and allocation requirements. Furthermore, on some architectures, such as the IA-64 , "overflow" might mean that two separate stack pointers allocated within the region will overlap somewhere in the middle of the region. FUTURE DIRECTIONS None. SEE ALSO pthread_attr_init(), pthread_attr_setdetachstate(), pthread_attr_setstacksize(), pthread_create(), <limits.h>, <pthread.h>. Rationale ------------- See the problem statement. Circulated for review: 26 Apr 2000 Proposed resolution: 26 Apr 2000 Approved: April 2000