Существуют практические ограничения для обратной совместимости. Во-первых, смешивание объектов из разных версий glibc
в одном исполняемом файле может иногда работать, но специально для такой совместимости ничего не предпринимается. Следует отметить, что это касается динамически загружаемых, а также статически связанных объектов. Во-вторых, приложение должно использовать только стандартные возможности glibc
. Приложение, которое зависит от побочных эффектов ошибок или основано на неопределенном поведении одной из версий glibc
, может не работать с более поздними версиями этой библиотеки. Приложение, компонуемое с приватными символами glibc
(обычно они имеют префикс а_
), также вряд ли будет работать с более новыми версиями glibc
.
Обратная совместимость поддерживается тогда, когда задействованы символы, разработанные специально для соответствия стандартам версий. Когда разработчики glibc
хотят внести несовместимое изменение в glibc
, они сохраняют оригинальную реализацию или пишут совместимую реализацию данного интерфейса и помечают его более старым номером версии glibc
. Затем они реализуют новый интерфейс (который может отличаться по семантике, сигнатуре или и тем, и другим) и помечают его новым номером версии glibc
. Приложения, построенные на базе старой версии glibc
, используют старый интерфейс, а приложения, построенные на основе новой версии — новый интерфейс.
Большинство других библиотек поддерживают совместимость, включая номер версии в имя библиотеки и позволяя множеству разных версий быть установленными одновременно. Например, инструментальные наборы GTK+ 1.2 и GTK+ 2.0 могут быть одновременно установлены в одной системе, каждый со своим собственным набором заголовочных и библиотечных файлов, путем встраивания в путь к заголовочным файлам и файлам библиотек имени версии.
Раздел стандарта по наименованию разделяемых библиотек в Linux включает старший номер версии для возможности установки в системе множества версий библиотеки. Это используется не очень часто, поскольку в одной системе невозможно скомпоновать новые приложения с множеством версий библиотеки; это просто обеспечивает поддержку лишь обратной совместимости для существующих приложений, построенных на более старых системах. На практике разработчикам требуется собирать приложения со многими версиями одной и той же библиотеки, поэтому большинство основных библиотек содержат в своем названии и номер версии.
Глава 7
Средства отладки использования памяти
Несмотря на то что С бесспорно является стандартным языком программирования в системах Linux, он имеет ряд особенностей, не дающих программистам возможности писать код, не содержащий тонких ошибок, которые впоследствии очень сложно отладить. Утечки памяти(когда память, выделенная с помощью malloc()
, никогда не освобождается посредством free()
) и переполнение буфера(например, запись за пределы массива) — наиболее распространенные и трудные для обнаружения программные ошибки. Недогрузка буфера(вроде записи перед началом массива) — менее распространенное, но обычно еще более тяжелое для отслеживания явление. В этой главе представлены несколько средств отладки, которые могут значительно упростить обнаружение и изоляцию упомянутых проблем.
7.1. Код, содержащий ошибки
1: / * broken.с* /
2:
3: #include
4: #include
5: #include
6:
7: char global[5];
8:
9: int broken(void){
10: char *dyn;
11: char local[5];
12:
13: /* Для начала немного перезаписать буфер */
14: dyn = malloc(5);
15: strcpy(dyn, "12345");
16: printf ("1: %s\n", dyn);
17: free(dyn);
18:
19: /* Теперь перезаписать буфер изрядно */
20: dyn = malloc(5);
21: strcpy(dyn, "12345678");
22: printf("2: %s\n", dyn);
23:
24: /* Пройти перед началом выделенного с помощью malloc локального буфера */
25: * (dyn-1) ='\0';
26: printf ("3: %s\n", dyn);
27: /* обратите внимание, что указатель не освобожден! */
28:
29: /* Теперь двинуться после переменной local */
30: strcpy(local, "12345");
31: printf ("4: %s\n", local);
32: local[-1] = '\0';
33: printf("5: %s\n", local);
34:
35: /* Наконец, атаковать пространство данных global */
36: strcpy(global, "12345");
37: printf ("6: %s\n", global);
Читать дальше