Проверка, является ли указатель выделенной памятью или нет

Проблема

В своем коде вы генерируете файл, который затем будет обслуживаться вашим API. Этот файл создается с помощью new java.io.FileOutputStream(filePath) и называется Resume2019-01-16.pdf в папке Downloads.

Поскольку вы используете свой API локально, при переходе к конечной точке браузер загрузит файл, который вы обслуживаете, в вашу папку Downloads. Поскольку Resume2019-01-16.pdf уже существует, браузер назовет его Resume2019-01-16 (1).pdf.

Следовательно, похоже, что два файла загружаются, но один генерируется вашим кодом, а другой - фактически загружен.

Исправить

Измените папку для файлов, которые вы обслуживаете, и в вашем Downloads появятся только фактически загруженные файлы, например:

String filePath = homePath + "/Documents/Resume" + LocalDateTime.now().toLocalDate() + ".pdf";
[ 1115] В качестве альтернативы используйте некоторый метод для сохранения вашего файла в памяти, вместо создания физического файла, и используйте его вместо этого.

68
задан sashoalm 8 June 2015 в 08:45
поделиться

11 ответов

Вы не можете проверить, за исключением некоторых хаков, связанных с реализацией.

Указатели не имеют никакой информации, кроме того, где они указывают. Лучшее, что вы можете сделать, это сказать: «Я знаю, как эта конкретная версия компилятора выделяет память, поэтому я разыменую память, переместу указатель на 4 байта назад, проверю размер, убедится, что он совпадает ...» и так далее. Вы не можете сделать это стандартным способом, поскольку распределение памяти определяется реализацией. Не говоря уже о том, что они могли вообще не выделять ее динамически.

Вам просто нужно предположить, что ваш клиент знает, как программировать на C. Единственное решение, которое я могу придумать, - это выделить память самостоятельно и вернуть ее, но это вряд ли небольшое изменение. (Это более крупное изменение дизайна.)

29
ответ дан 24 November 2019 в 14:22
поделиться

Я не знаю, как это сделать с помощью библиотечного вызова, но в Linux вы можете посмотреть /proc/<pid>/numa_maps. Он покажет все разделы памяти, а в третьем столбце будет написано «куча» или «стек». Вы можете посмотреть на необработанное значение указателя, чтобы увидеть, где оно выстраивается.

Пример:

00400000 prefer:0 file=/usr/bin/bash mapped=163 mapmax=9 N0=3 N1=160
006dc000 prefer:0 file=/usr/bin/bash anon=1 dirty=1 N0=1
006dd000 prefer:0 file=/usr/bin/bash anon=9 dirty=9 N0=3 N1=6
006e6000 prefer:0 anon=6 dirty=6 N0=2 N1=4
01167000 prefer:0 heap anon=122 dirty=122 N0=25 N1=97
7f39904d2000 prefer:0 anon=1 dirty=1 N0=1
7f39904d3000 prefer:0 file=/usr/lib64/ld-2.17.so anon=1 dirty=1 N0=1
7f39904d4000 prefer:0 file=/usr/lib64/ld-2.17.so anon=1 dirty=1 N1=1
7f39904d5000 prefer:0 anon=1 dirty=1 N0=1
7fffc2d6a000 prefer:0 stack anon=6 dirty=6 N0=3 N1=3
7fffc2dfe000 prefer:0

Таким образом, указатели, которые выше 0x01167000, но ниже 0x7f39904d2000, расположены в куче.

1
ответ дан Mark Lakata 24 November 2019 в 14:22
поделиться

Неинициализированный указатель и есть неинициализированный. Он может указывать на что угодно или просто быть недействительным адресом (т. Е. Адресом, не отображенным в физическую или виртуальную память).

Практическое решение состоит в том, чтобы иметь подпись действительности в объектах, на которые указывают. Создайте оболочку malloc (), которая выделяет запрошенный размер блока плюс размер структуры подписи, создает структуру подписи в начале блока, но возвращает указатель на место после подписи. Затем вы можете создать функцию проверки, которая принимает указатель, использует отрицательное смещение для получения структуры действительности и проверяет ее. Вам, конечно же, понадобится соответствующая оболочка free (), чтобы сделать блок недействительным, перезаписав подпись действительности, и выполнить освобождение от истинного начала выделенного блока.

В качестве структуры действительности, вы можете использовать размер блока и его дополнение. Таким образом, у вас будет не только способ проверки блока (XOR двух значений и сравнение с нулем), но и информация о размере блока.

0
ответ дан 24 November 2019 в 14:22
поделиться

Нет, нельзя. Вы заметите, что никакие функции в стандартной библиотеке или где-либо еще не делают этого. Это потому, что нет стандартного способа сказать. Вызывающий код просто должен взять на себя ответственность за правильное управление памятью.

0
ответ дан 24 November 2019 в 14:22
поделиться

Вы не можете проверить с помощью чего-либо, доступного в стандарте C. Даже если бы ваш конкретный компилятор предоставил функцию для этого, это все равно было бы плохой идеей. Вот пример того, почему:

int YourFunc(char * buf, int buf_size);

char str[COUNT];
result = YourFunc(str, COUNT);
1
ответ дан 24 November 2019 в 14:22
поделиться

Один из способов взлома, который вы можете попробовать, - это проверить, указывает ли ваш указатель на выделенную стеком память. Это не поможет вам в целом, так как выделенный буфер может быть слишком маленьким или указатель указывает на какой-либо раздел глобальной памяти (.bss, .const, ...).

Для выполнения этого взлома вы сначала сохраняете адрес первая переменная в main (). Позже вы можете сравнить этот адрес с адресом локальной переменной в вашей конкретной программе. Все адреса между обоими адресами находятся в стеке.

2
ответ дан 24 November 2019 в 14:22
поделиться

Нет, в общем случае это невозможно.

Кроме того, если ваш интерфейс просто «передает указатель на буфер, в который я буду помещать материал», то вызывающий может выберите , а не , чтобы выделить память вообще, и вместо этого используйте буфер фиксированного размера, который выделяется статически, или автоматическую переменную, или что-то еще. Или, возможно, это указатель на часть более крупного объекта в куче.

Если в вашем интерфейсе специально указано «передать указатель на выделенную память (потому что я собираюсь его освободить)», то вы должны ожидать, что вызывающий будет делать так. Невыполнение этого требования нельзя надежно обнаружить.

2
ответ дан 24 November 2019 в 14:22
поделиться

Обычно пользователи библиотеки несут ответственность за проверку и проверку ввода. Вы можете увидеть ASSERT или что-то еще в коде библиотеки, и они используются только для отладки. это стандартный способ написания C / C ++. в то время как многие программисты любят очень тщательно проверять и проверять свой код библиотеки. действительно "ПЛОХИЕ" привычки. Как указано в IOP / IOD, интерфейсы lib должны быть контрактами и четко указывать, что будет делать lib, а что нет, и что должен делать пользователь lib, а что не должно быть необходимым.

0
ответ дан 24 November 2019 в 14:22
поделиться

Я всегда инициализирую указатели нулевым значением. Поэтому, когда я выделяю память, она изменится. Когда я проверяю, выделена ли память, я делаю указатель ! = NULL . Когда я освобождаю память, я также устанавливаю указатель на ноль. Я не могу придумать способ узнать, достаточно ли выделенной памяти.

Это не решает вашу проблему, но вы должны верить, что если кто-то пишет программы на C, то он достаточно квалифицирован, чтобы делать это правильно.

4
ответ дан 24 November 2019 в 14:22
поделиться

Как все говорили, стандартного способа сделать это не существует.

Пока еще никто не упомянул « Написание твердого кода » автора Стив Магуайр. Несмотря на критику в некоторых кругах , в книге есть главы, посвященные управлению памятью, и обсуждается, как с осторожностью и полным контролем над всем распределением памяти в программе вы можете делать то, что вы просите, и определять, Указанный вами указатель является действительным указателем на динамически выделяемую память. Однако, если вы планируете использовать сторонние библиотеки, вы обнаружите, что некоторые из них позволяют изменять процедуры выделения памяти на свои собственные, что значительно усложняет такой анализ.

1
ответ дан 24 November 2019 в 14:22
поделиться

Для решения для конкретной платформы вас может заинтересовать функция Win32 IsBadReadPtr (и другие подобные). Эта функция сможет (почти) предсказать, возникнет ли ошибка сегментации при чтении из определенного фрагмента памяти.

Однако это не защищает вас в общем случае, потому что операционная система ничего не знает о диспетчере кучи среды выполнения C, и если вызывающий объект передает буфер, размер которого не такой большой, как вы ожидали, тогда остальная часть блока кучи будет по-прежнему доступна для чтения с точки зрения ОС.

9
ответ дан 24 November 2019 в 14:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: