Бинарные переменные окружения и setenv()

Играя с бинарными переменными среды в Linux, я обнаружил странное поведение, когда некоторые отдельные байты были неверными. Я изучил его поближе, и кажется, что определенные байты всегда будут «преобразовываться» неправильно, если они переданы в setenv(). Посмотри на это:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    char array[256];

    int i;
    for(i = 1; i < 256; i++) {
        array[i] = i;
    }

    setenv("badenv", array, 1);

    system("/bin/sh");

    return 0;
}

Я запускаю эту программу, затем, когда я делаю echo $badenv > test; шестнадцатеричный тест я вижу:

0000000 0101 0302 0504 0706 2008 0c0b 0e0d 100f
0000010 1211 1413 1615 1817 1a19 1c1b 1e1d 201f
0000020 2221 2423 2625 2827 2a29 2c2b 2e2d 302f
0000030 3231 3433 3635 3837 3a39 3c3b 3e3d 403f

Похоже, что 0x9 преобразуется в 0x20, а 0xa преобразуется, среди прочего, в 0xb.

Злоупотребляю ли я setenv() или, может быть, вообще злоупотребляю переменными окружения? Я просмотрел справочную страницу и обыскал некоторые, чтобы узнать, должны ли переменные среды обрабатывать двоичные значения или нет, но я не уверен.

В чем причина такого поведения, есть ли способ обойти это, все еще используя переменные среды?


person csstudent2233    schedule 02.04.2013    source источник
comment
Кажется, есть какое-то молчаливое ограничение на то, что может быть в переменной env. export a=echo -e \t` дает то же самое, заменив табуляцию пробелом.   -  person elmo    schedule 02.04.2013
comment
Поскольку setenv ожидает в качестве значения переменной строку, заканчивающуюся 0 (также известную как строка в стиле C), значение, очевидно, не может быть произвольным двоичным данными, потому что оно не будет хорошо обрабатывать 0 байтов. Я не знаю, почему он преобразует управляющие символы, такие как 0x9, в пробелы. Скорее всего какая-то мера безопасности.   -  person shakurov    schedule 02.04.2013


Ответы (1)


Переменная окружения разбивается на «слова» в соответствии со значением $IFS, а «слова» соединяются одним разделителем — в данном случае обычным пробелом. Таким образом, последовательность "\x09\x0a" или "\t\n", сворачивается в один пробел ('\x20') при интерпретации содержимого array.

IFS — внутренний разделитель полей, который используется для разделения слов после расширения и для разделения строк на слова с помощью встроенной команды чтения. Значение по умолчанию — ''новая строка табуляции пробела''.

Вы можете избежать замены, (временно) изменив $IFS.

Обратите внимание, однако, что

  • array[0] имеет неопределенное значение
  • array не заканчивается 0

в вашей программе. Вы должны исправить это.

person Daniel Fischer    schedule 02.04.2013
comment
Спасибо, а что мне нужно установить для $IFS, чтобы получить такое поведение? В настоящее время $IFS не установлен, я попытался просто объявить его без содержимого. - person csstudent2233; 02.04.2013
comment
Вы можете установить IFS=" ", тогда (непустая) последовательность пробелов будет свернута в один пробел, но, поскольку есть только один пробел, он не будет изменен. Но я почти уверен, что IFS установлено, echo -n "$IFS" | xxd должно сказать вам, что (вероятно, пробел, табуляция, новая строка, поэтому xxd сообщит 2009 0a). - person Daniel Fischer; 02.04.2013
comment
Да, ты прав. Еще раз спасибо, кажется, это работает и в моей оригинальной игрушечной программе. Программа, которую я вставил сюда, была просто чем-то, чтобы продемонстрировать проблему в целом. - person csstudent2233; 02.04.2013