2016よーめー日記2016年2月26日金曜日C++の共有ライブラリをdlsymで呼び出すC++で共有ライブラリを作って、dlsym()でクラスメソッドを動的に呼び出す場合、どうすればよいのか調べてみました。ネットでよく出回っている方法は、MicrosoftがComponentObjectModelで昔よく使っていたクラスメソッドにすべてvirtualをつけて宣言し、クラスを作ったり破棄したりするC言語形式のファクトリー関数を用意する方法です。a;}------------------------------------上記の例で説明するとdlsym()でcreate_cppdll()のアドレスを取得して関数を呼び出せば、あとはCcppdllのポインタ経由でメンバー変数と仮想関数の呼び出しができます。virtualで宣言したメンバ関数はコンストラクタで作られる仮想関数テーブル経由で関数が呼び出されるので、共有ライブラリ内でのシンボル名が解決していなくてもよいんです。C++のクラスって、オペレーター演算子の関数が定義されてたり、テンプレートが使われていたりします。長年の疑問だったのですが、そういう場合、動的ロードできるのか調べてみました。オペレータ演算子のメソッド関数。この関数そもそもvirtualにできるんですかね?調べてみた結果、なんとできます。すごいねぇ、オペレーターメソッド関数って仮想関数にできるのね。次にテンプレート関数。この関数はvirtualにできません。そりゃーそうでしょう。テンプレートだから、C++のクラスの仮想関数テーブルの関数の順番が特定できないからね。テンプレート関数はstaticな無名外部関数に展開されるはずなので、テンプレート関数内部で使っている関数がすべて仮想関数ならばコンパイルが通り動的にロードできます。共有2016年2月25日木曜日MySQLとSQLiteを切り替える今週はデータベースの勉強期間なのでデータベースネタをもう一つ。これでデータベース系は最後です。僕、SQLiteって軽くて高速なので、大好きでよく使います。スマートフォンなどのクライアント側はSQLiteが主に使われているのに、サーバ側はMySQLがメインで、使用するデータベースが違っていてサーバとクライアントで共通化できなくて困ります。SQLiteでさくっとプロトタイプを作って、あとからMySQLに移行してリプリケーションさせてスケールさせることもよくあります。MySQLって商用のサーバ運用するときにはとっても便利なんですが、ローカルでWebAPIとかを開発するときは自分のPCにインストールするのがめんどくさい。どの言語のどのインタフェースで書くかにもよるのですが、MySQLとSQLiteの両方で動くようにするには関数のインタフェースって微妙に違っていて困ります。JavaだとJDBCがあるのですが、JDOとかPDOとかODBCとか共通化規格がそもそも共通化されてないし。データベースってSQL文投げて複数の行が返ってくるだけなのに、なんでこう関数が違うんでしょうね。簡単なラッパーでよいんでない?ということで、MySQLとSQLiteを直接切り替えて呼び出せるラッパー関数を作ってみました。僕は高速に動作するC/C++が大好きなので、実装はいつものようにC/C++ですが、ほかの言語でも同じようにすれば複数のデータベースを併用することができます。前回のブログで書いたMySQLの関数の動的呼び出しを行っているので、ビルド時にMySQLのライブラリはいりません。これで簡単にデータベースを切り替えられる!ローカルで開発とかデバッグするときはSQLiteで行い、最終運用はMySQLで行うというようにデータベースを使い分けることや、サーバとクライアントでコードを共通化することもできます。C言語なのでAndroid、iPhone、Linuxサーバ、Windowsサーバどれでも動くしとても便利。共有2016年2月22日月曜日MySQLを動的にリンクする久しぶりにデータベースの勉強をしようと思い僕のWindowsマシンにMySQLを入れてみました。ところがMySQLをC言語から使おうとするとVisualStudio2013までしかサポートしていません。最新のVisualStudio2015をいれたのに。これでは最新の開発でMySQL使えないじゃん。このようなVisualStudioやGCCのバージョン依存問題って本当によく起こるのでこれらを解決する方法を考えてみました。考えること一時間、MySQLの関数を動的にリンクして呼び出せばよいのではないかと思い、MySQLの動的呼び出しラッパーをつくってみました。余談ですが、MySQLのコード書いている人、とても正しくきれいにコーディングできていてすごいですね。OpenSSLなんて汚くて汚くて。0;}----------------------------------------やったー、動いた。テストプログラムもちゃんと動きました。この方法、OpenCVなどC++で書かれているライブラリだと使えませんが、OpenSSLなどC言語で書かれているほかのライブラリでも使えます。共有2016年2月16日火曜日セキュアでないセキュアプログラミングお仕事でプログラムをするときは、たとえば長い文字列を渡されてプログラムが攻撃されても大丈夫なようにセキュアプログラミングをしないといけません。言語ごとにセキュアプログラミングのポイントが異なるのですが、とくにC言語はセキュアにプログラムをするのが本当に難しいです。アップルとかは以下のガイドラインを出してます。DeveloperこれにもC言語でセキュアプログラミングをする場合、「sprintf()、vsprint()でなくてsnprintf()、vsnprint()を使いましょう」って書いてあります。2013のC++のsnprintf()、vsnprint()は文字列が指定したサイズをオーバーしそうになった場合、文字列をnullで終端しません。snprintf()を使って文字列を切り捨てているLinuxアプリをWindowsに移植するとへんな文字列が表示されたりプログラムが落ちます。ANSI規格でnull終端する決まりになっていますが、決まりができるより前からあるVisualStudioではそうなっていないのです。MSDNにも以下のように書かれています。指すメモリに書き込みます。----------------------なんでしょうね。このへたくそな解説と翻訳。nullで終わりますって書いてあるけど、よく読むと条件付きでnullで終わります。nullでおわるとは限らないのです。英語文化圏の人にはわかりやすいんでしょうがこれが日本語の壁というかなんというか。ひどい会社とかのルールになるとstrcpy()、strcat()の代わりにstrncpy()、strncat()を使いましょうっていうのもあります。このルール作ったの誰だよ!これもそうとう怪しいです。strncpy()もVisualStudioのsnprintf()と同様にnullで終端しない可能性があるし、strncat()にいたっては連結する最大文字列であってバッファの最大サイズではないんです。strcpy()、strcat()を使ってはいけないまではあっているのに・・・・。何が安全なのかさっぱりわかりません。C言語のセキュアプログラミングについてどれも信用できないし、strcpy()、strcat()、sprintf()、snprintf()の関数って結構便利で使いたいですよね。C言語の場合どの解説もよい代替案がないので、それが問題なんですよね。解決策として、マイクロソフトはマイクロソフトがセキュリティー開発ライフサイクル(SDL)プログラミングっていうのを推奨しています。これによると、マイクロソフトはstrcpy_s()、strcat_s()、sprintf_s()、snprintf_s()という関数を使用することを推奨していますが、これってLinuxにないので困ります。アップルは上記にあげた先ほどのガイドラインで、strlcpy()とstrlcat()を使うことを推奨しています。これもMacOSXとかiPhoneでしか動かない。「僕だったらこう作ります。」というstrcpy_y()、strcat_y()、sprintf_y()を作ってみました。基本的にはアップルと同じものをアップル以外にも動くようにした感じで、マイクロソフトの良いところも取り入れてみました。書けばどのOSでも動くし、#include"safestring.h"すれば出力バッファが関数内で定義されているという条件付きですがstrcat()とかsprintf()とかそのままでも結構安全に動きます。一流企業でもセキュアプログラミングの方針が全く違うので、C言語での標準化なんて出来そうにないですね。C言語でのセキュアプログラミングのやり方って難しいんですね。