Usandoffprobe
#!/bin/bash
for file in *.mp3
do
brate=$(ffprobe "$file" |& grep -Eo 'bitrate: [0-9]+' | cut -d' ' -f2)
if [[ "$brate" -gt 128 ]]
then
newname=$(basename "$file" -smaller.mp3)
ffmpeg -i "$file" -acodec libmp3lame -ac 2 -ab 128k -ar 44100 "${newname}.mp3"
fi
done
Память, возвращаемая malloc (), не инициализирована нулем -. Никогда не думайте, что это так.
В вашей тестовой программе это просто случайность. :Я думаю, что malloc()
только что получил новый блок mmap()
, но не полагайтесь и на это.
Например, если я запускаю вашу программу на своем компьютере таким образом:
$ echo 'void __attribute__((constructor)) p(void){
void *b = malloc(4444); memset(b, 4, 4444); free(b);
}' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so
$ LD_PRELOAD=./pollute.so./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036
Ваш второй пример просто показывает артефакт реализации malloc
в glibc; если вы повторите malloc
/ free
с буфером размером более 8 байт, вы ясно увидите, что обнуляются только первые 8 байтов, как в следующем примере кода.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
const size_t n = 4;
const size_t m = 0x10;
int main()
{
for (size_t i = n; i; --i) {
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j) {
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);
}
free(p);
printf("\n");
}
return 0;
}
Выход:
0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4
Независимо от того, как инициализируется стек, вы не видите нетронутый стек, потому что библиотека C выполняет ряд действий перед вызовом main
, и они касаются стека.
В библиотеке GNU C на платформе x86 -64 выполнение начинается с точки входа_start , которая вызывает__libc_start_main
для настройки, а последняя завершается вызовом main
. Но перед вызовом main
он вызывает ряд других функций, что приводит к записи в стек различных фрагментов данных. Содержимое стека не очищается между вызовами функций, поэтому, когда вы попадаете в main
, ваш стек содержит остатки от предыдущих вызовов функций.
Это объясняет только результаты, которые вы получаете из стека, см. другие ответы, касающиеся вашего общего подхода и предположений.
В обоих случаях вы получаете неинициализированную память и не можете делать никаких предположений о ее содержимом.
Когда ОС должна выделить новую страницу для вашего процесса (, будь то для своего стека или для арены, используемой malloc()
), она гарантирует, что не будет раскрывать данные из других процессов; обычный способ гарантировать это — заполнить его нулями (, но в равной степени можно перезаписать чем-нибудь другим, включая даже страницу стоимостью/dev/urandom
-на самом деле, некоторые отладочные malloc()
реализации записывают не -нулевые шаблоны, поймать ошибочные предположения, такие как ваше ).
Если malloc()
может удовлетворить запрос из памяти, уже использованной и освобожденной этим процессом, ее содержимое не будет очищено (по сути, очистка не имеет отношения к malloc()
и не может быть -это должно произойти до того, как память будет отображена в ваше адресное пространство ). Вы можете получить память, которая ранее была записана вашим процессом/программой (, например. передmain()
).
В вашей программе-примере вы видите область malloc()
, которая еще не была записана этим процессом (, т. е. она непосредственно взята с новой страницы )и стека, который был записан в (. ] с помощью предварительного кода-main()
в вашей программе ). Если вы исследуете больше стека, вы обнаружите, что он заполнен нулями -ниже (в направлении роста ).
Если вы действительно хотите понять, что происходит на уровне ОС, я рекомендую вам обойти уровень библиотеки C и вместо этого взаимодействовать с помощью системных вызовов, таких как brk()
и mmap()
.
Ваша предпосылка неверна.
То, что вы описываете как «безопасность», на самом деле является конфиденциальностью , что означает, что ни один процесс не может читать память другого процесса, если только эта память явно не разделена между этими процессами. В операционной системе это один из аспектов изоляции параллельных действий или процессов.
Что делает операционная система для обеспечения этой изоляции, так это то, что всякий раз, когда процесс запрашивает память для выделения кучи или стека, эта память поступает либо из области физической памяти, которая заполнена нулями, либо заполнена мусор, исходящий из того же процесса .
Это гарантирует, что вы когда-либо будете видеть только нули или свой собственный мусор, поэтому гарантируется конфиденциальность, и как куча , так и стек являются «безопасными», хотя и не обязательно (ноль -)инициализирован.
Вы слишком много читаете в своих измерениях.