اشاره‌گرهای معلق

دلایل بروز اشارهگرهای معلق

در بسیاری از زبان های برنامه نویسی، مانند C، وقتی یک شی از محدوده خارج می‌شود یا صریحاً دستور خالی شدن دریافت می‌کند، اشارهگرهایی که به ان شی اشاره میکنند تغییر نمی‌کنند.
به عنوان مثال به کد زیر توجه کنید:
{
   char *dp = NULL;
   /* ... */
   {
       char c;
       dp = &c;
   } /* c falls out of scope */
     /* dp is now a dangling pointer */}
در صورتی که سیستم عامل بتواند اشاره‌گرهایی که به پیوندهای پوچ میرسند، شناسایی کند، می‌تواند آن‌ها را برابر 0 یا NULL قرار دهد. یک راه دیگر این است که به‌طور مثال اجازه داده نشود dp دوباره استفاده شود.
یک راه دیگر به وجود امدن اشاره‌گر معلق، استفاده همزمان تابع malloc و در ادامه free است. در واقع بعد از اینکه یک اشارهگر با malloc مقداردهی می‌شود توسط free خالی می‌شود و اشارهگر استفاده شده معلق می‌شود. به کد زیر توجه کنید:
#include <stdlib.h>void func(){
    char *dp = malloc(A_CONST);
    /* ... */
    free(dp);         /* dp now becomes a dangling pointer */
    dp = NULL;        /* dp is no longer dangling */
    /* ... */}
یک اشتباه رایج استفاده از ادرس متغیرهای محلی در یک تابع است که با برگرداندن یک اشارهگر به ان قسمت، ان اشارهگر را معلق می‌کند. چرا که اشارهگر استفاده شده به جایی از حافظه اشاره می‌کند که پس از اتمام اجرای تابع خالی شده و دیگر تضمینی بر حفظ مقادیر وجود ندارد. 
int *func(void){
    int num = 1234;
    /* ... */
    return &num;}
تلاش برای خواندن مقدار برگشت داده شده از تابع، پس از اندکی بعد از فراخوانی ان تابع ممکن است نتیجه 1234 را برگرداند اما در ادامه برنامه احتمالاً ان حافظه برای استفاده دیگری اختصاص خواهد یافت و مقدار مورد نظر ما، پاک خواهد شد.

دلایل به وجود امدن اشارهگرهای وحشی

اشارهگرهای وحشی زمانی به وجود میایند که اشارهگرها قبل از اولین استفاده، مقداردهی نشده باشند. در واقع زمانی که یک اشارهگر مقداردهی اولیه نمی‌شود، ان اشارهگر حتماً وحشی است. به مثال زیر توجه کنید:
int f(int i){
    char *dp;    /* dp is a wild pointer */
    static char *scp;  /* scp is not a wild pointer:                        * static variables are initialized to 0                        * at start and retain their values from                        * the last call afterwards.                        * Using this feature may be considered bad                        * style if not commented */}

سوراخ های امنیتی مرتبط

مانند سرریز بافر، اشارهگرهای معلق به راحتی به سوراخ‌های امنیتی تبدیل می‌شوند. برای مثال اگر یک اشارهگر بخواهد یک تابع virtual function را فراخوانی کند، در صورتی که اشارهگر دستکاری شده باشد، یک ادرس دیگر می‌تواند فراخوانی شود که ممکن است دستور اجرای یک فرایند خرابکارانه باشد.

روشهای جلوگیری

در زبان برنامه‌نویسی C/C++ راحتترین روش قابل استفاده، استفاده از یک تابع جایگزین برای free یا استفاده از تابع delete در زمان مناسب است. به هر حال با این روش، تنها برای یک اشارهگرهایی اثربخش است که مستقیماً توسط توابع تعریف شده خالی شوند، اما سایر اشارهگرها را از حال معلق خارج نمی‌سازد.
#include <assert.h>#include <stdlib.h>/* Alternative version for 'free()' */void safefree(void **pp){
    /* in debug mode, abort if pp is NULL */
    assert(pp);
    if (pp != NULL) {               /* safety check */
        free(*pp);                  /* deallocate chunk, note that free(NULL) is valid */
        *pp = NULL;                 /* reset original pointer */
    }}int f(int i){
    char *p = NULL, *p2;
    p = (char *)malloc(1000);    /* get a chunk */
    p2 = p;              /* copy the pointer */
    /* use the chunk here */
    safefree((void **)&p);       /* safety freeing; does not affect p2 variable */
    safefree((void **)&p);       /* this second call won't fail */
    char c = *p2;       /* p2 is still a dangling pointer, so this is undefined behavior. */
    return i + c;}
راه حل دیگر این است که قبل از استفاده از malloc() اشارهگر بررسی شود و در صورت معلق بودن 0 مقداردهی شود.
    safefree(&p);        /* i'm not sure if chunk has been released */
    p = malloc(1000);    /* allocate now */
این راهکارها می‌تواند توسط یک دستور #define با ایجاد چند ماکرو مفید، خلاصه شود. به هر شکل، این برنامه‌نویس است که باید تصمیم بگیرد از توابع امن استفاده کند. در صورت عدم استفاده از این توابع مشکلات اشارهگرهای معلق باز هم برمیگردد.
یک روش دیگر که قابل استفاده در راهکارهایی که بشتر ساختاریافته هستند استفاده از اشارهگر هوشمند است. اشارهگر هوشمند، به این شکل عمل می‌کند که تعداد اشارهگرها به یک شی را میشمارد و زمانی که نیاز به ازاد سازی حافظه شد، با ازاد سازی ان شی، تمام اشارهگرهای ان را هم به NULL تغییر میدهد. 
روش دیگر استفاده از تکنیک Garbage Collection استف. در این حالت این سیستم عالم است که حساب اشارهگرهای برنامه اجرا شده را در اختیار میگیرد و در صورتی که شی پیدا شود که اشارهگری به ان اشاره نمی‌کند، ان شی را از حافظه پاک می‌کند. این روش به کلی احتمال بروز اشارهگرهای معلق را از بین میبرد.
در زبانهای برنامه نویسی سطح بالا، مانند JAVA، امکان بروز اشارهگر معلق وجود ندارد، چرا که هیچ روش مستقیمی برای خالی کردن حافظه در این زبان تعبیه نشده و تمام ازادسازی حافظه توسط Garbage Collector انجام می‌شود.

روش شناسایی

یک روش این است که تمام اشارهگرها را تا قبل از مقدار دهی برابر 0 یا null pointer قرار دهیم، همین روش باید برای اشارهگرهایی که مقادیر مرتبط با ان ازادسازی شده‌اند استفاده شود.  اشارهگهر null خطری برای استفاده ندارد و در هیچ سیستم کامپیوتری استفاده از ان منجر به از دستگاری داده ها و خرابکاری نمی‌شود. در بیشتر کامپایلرها با فراخوانی یا خواندن مقدار null pointer برنامه متوقف می‌شود و ادامه نمی‌یابد.