Когнитивный диссонанс

Вчера я был поражен на столько, что усомнился в том, во что верил уже лет 10. А именно в том, что при выравнивании 8, размер структур с полями {u64, u32, u16} и {u8, u32, u16} будет одинаков, т.е. равен 16. А ведь приложение собранное Rust утверждает что в первом случае размер 16, что и следовало ожидать, а во втором 12(!!!).

type tuple_type1 = (u64, u32, u16);
type tuple_type2 = (u8, u32, u16);

fn main() {
    io::println(#fmt("size of tuple_type1 = %u, size of tuple_type2 = %u",
        sys::size_of::<tuple_type1>(), sys::size_of::<tuple_type2>()));
    io::println(#fmt("align of tuple_type1 = %u, align of tuple_type2 = %u",
        sys::align_of::<tuple_type1>(), sys::align_of::<tuple_type2>()));
}

Содержимое консоли:

> ./main
size of tuple_type1 = 16, size of tuple_type2 = 12
align of tuple_type1 = 8, align of tuple_type2 = 8

Continue reading

Миф о Java

Про языки с автоматическим управлением памятью в целом и про Java в частности существует один довольно забавный миф – приложения с автоматическим управлением памяти не текут или текут редко. Бугагашеньки.

Берем известное и крайне популярное среди Java-разарботчиков приложение Intellij IDEA. Открываем в этом приложении большой проект (на мелком не так в глаза бросается) и работаем. Ближе к концу второго-третьего дня работы приложения, объем используемой памяти вырастает с изначальных 300 мегабайт до 700 и IDEA начинает ощутимо тормозить. Полагаю, что дальше будет только больше, лично мне на 700 это дело надоело, и я перезапустил приложение.

Что вобщем-то и требовалось доказать, напортачить можно даже на том языке, где создатели выдали тебе специальный не снимаемый памперс – было бы желание.

using namespace std

В кругах разработчиков C++ периодически возникает спор на тему “почему нельзя/нужно использовать using namespace std“. Наткнулся на довольно показательный пример того, почему этого делать ни в коем случае нельзя.
Товарищ пытается написать удаление пробелов из строки:

#include <iostream>

#include <string>

using namespace std;

int main(int argc, char* argv[]) {
    string str = "";
    cin >> str;
    remove(str.begin(), str.end(), ' ');
    cout << str;
    cin.ignore();
}

и получет довольно неожиданную ошибку компиляции.

'remove': function does not take 3 arguments (C2660)

А все почему? Да потому-что никогда, ни при каких условиях, не надо давать символам из пространства std глобальную видимость! Ведь в данном случае, можно было получить куда более понятное “error: ‘remove’ was not declared in this scope” просто убрав using namespace std.

Java + Ant + сетевой диск

Java – наверное самая уродская платформа из всех, с какими я имел дело. Ну и Ant не дальше ушел.
Итак, дано: Linux, сетевой диск с парой гагабай исходников, ant, java, gcc. Простейшая команда ant clean приводит к исключению java.lang.OutOfMemoryError. Перепробовал все найденные в интернете способы изменения объема используемой памяти и прочих шаманских действий – не помогает.
Стал эксперементировать дальше, выяснил, что падает только на сетевых шарах(!!!). Скопировал локально – полет нормальный. Спрашиватся, ну какого хера ошибка OutOfMemoryError, а не что-то подходящее в данной ситуации?!
Вобщем, осталось только процесс копирования автоматизировать.

fstab

Это прям какая-то магия, но каждый раз когда я сталкиваюсь с fstab, у меня уходит куча времени на то чтобы в него что-то прописать. На этот раз мне понадобилось добавить Windows-шары на машину с Fedora 15. И теперь я решил все записать, чтоб уж в следующий раз точно не забыть как же это делается. Continue reading

CMake & Clang

Решил изменить сборку с идущего по умолчанию GCC на Clang для CMake проекта. Сходу наткнулся на граблю. Стандартная команда CMake:

set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_C_COMPILER clang)

Вводит его в вечный цикл, который выглядит как-то так:

You have changed variables that require your cache to be deleted.
Configure will be re-run and you may have to reset some variables.
The following variables have changed:
CMAKE_C_COMPILER= /usr/bin/gcc
CMAKE_CXX_COMPILER= /usr/bin/c++

-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Checking whether C compiler has -isysroot
-- Checking whether C compiler has -isysroot - yes
-- Checking whether C compiler supports OSX deployment target flag
-- Checking whether C compiler supports OSX deployment target flag - yes
…и так до бесконечности…

Лечится не удобно, но юзабельно:

export CXX=/usr/bin/clang++
export CC=/usr/bin/clang
cmake CMakeLists.txt
make

А GCC предупреждал…

Есть некий код, приблизительно следующего содержания (упрощенный вариант):

TRACE((ERROR, "Bla-bla-bla. Can't create struct (%terr)", err));

Причем, как мы выяснили с большим трудом, переменная err, это не некий интовый код ошибки, а млять C++ класс! (луч поноса автору этого говна). G++ это дело находит, и, пишет предупреждение:

warning: cannot pass objects of non-POD type ‘struct cERROR’ through ‘...’; call will abort at runtime

Но это предупреждение остается незамеченным среди остальных over 9000 предупрежденией. Но G++ не просто намекает, он еще и генениует вот такой код:

0x01d4fe77 :    mov    DWORD PTR [ebp-0x20],eax
0x01d4fe7a :    jmp    0x1d4fe7e <_ZN8KLParams11DeserializeERP13cSerializablej+668>
0x01d4fe7c :    ud2a  
0x01d4fe7e :    mov    eax,DWORD PTR [ebp-0x20]

Где “ud2a” is the guaranteed illegal opcode on ia32. Пацан сказал – пацан сделал.

Undefined Behavior для C разработчиков

Очень интересная серия статей посвященных Undefined Behavior от Криса Чембера, одного из авторов LLVM.
What Every C Programmer Should Know About Undefined Behavior #1/3
What Every C Programmer Should Know About Undefined Behavior #2/3
What Every C Programmer Should Know About Undefined Behavior #3/3

cURL & Proxy & HTTPS & Authorization == CURLE_RECV_ERROR

Да, баги в тулзах преследуют меня всю неделю. На сей раз отличился cURL с древним багом связанным с запросом отправляемым по HTTPS через прокси. Похоже что ситуация не слишком распространенная, т.к. надо не только работать через прокси, но еще на прокси должна быть включена авторизация и при отправке запроса пароль должен быть не указан. В принципе, в такой ситуации ожидаешь код 407, просишь пользователя ввести пароль и наступает счастье. Но вот cURL думает иначе. Вместо того чтоб вернуть 407 и страничку с ошибкой от прокси, которые судя по его логу присутствуют, зачем-то возвращается CURLE_RECV_ERROR.

Ignore 1380 bytes of response-body
Received HTTP code 407 from proxy after CONNECT
Closing connection #0
Failure when receiving data from the peer

Какого-либо корректного выхода из данной ситуации я не нашел. Так что, при работе через прокси, если пароль не задан и возникает ошибка CURLE_RECV_ERROR, единственное что остается – повторить запрос, предварительно указав параметры авторизации на проксе.