From ebe3c8c73d1ea7149309dc145c12af9779634563 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Tue, 20 Feb 2024 14:39:53 +0300 Subject: [PATCH 01/56] Add global _SESSION variable --- builtin-functions/_functions.txt | 2 ++ compiler/data/var-data.cpp | 2 +- compiler/vertex-util.cpp | 3 ++- runtime/interface.cpp | 3 ++- runtime/interface.h | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/builtin-functions/_functions.txt b/builtin-functions/_functions.txt index 16077a9bc4..42875a11f1 100644 --- a/builtin-functions/_functions.txt +++ b/builtin-functions/_functions.txt @@ -123,6 +123,8 @@ global $_COOKIE; global $_REQUEST; /** @var mixed $_ENV */ global $_ENV; +/** @var mixed $_SESSION */ +global $_SESSION; /** @var mixed $argc */ global $argc; /** @var mixed $argv */ diff --git a/compiler/data/var-data.cpp b/compiler/data/var-data.cpp index 5aebcaaf27..148236076a 100644 --- a/compiler/data/var-data.cpp +++ b/compiler/data/var-data.cpp @@ -35,7 +35,7 @@ const ClassMemberInstanceField *VarData::as_class_instance_field() const { // TODO Dirty HACK, should be removed bool VarData::does_name_eq_any_builtin_global(const std::string &name) { static const std::unordered_set names = { - "_SERVER", "_GET", "_POST", "_FILES", "_COOKIE", "_REQUEST", "_ENV", "argc", "argv", + "_SERVER", "_GET", "_POST", "_FILES", "_COOKIE", "_REQUEST", "_ENV", "_SESSION", "argc", "argv", "MC", "MC_True", "config", "Durov", "FullMCTime", "KPHP_MC_WRITE_STAT_PROBABILITY", "d$PHP_SAPI"}; return names.find(name) != names.end(); diff --git a/compiler/vertex-util.cpp b/compiler/vertex-util.cpp index 7f6d1606c8..0a1717a16f 100644 --- a/compiler/vertex-util.cpp +++ b/compiler/vertex-util.cpp @@ -124,7 +124,8 @@ bool VertexUtil::is_superglobal(const std::string &s) { "_FILES", "_COOKIE", "_REQUEST", - "_ENV" + "_ENV", + "_SESSION" }; return vk::contains(names, s); } diff --git a/runtime/interface.cpp b/runtime/interface.cpp index 5a0432f01c..5686a2ffe2 100644 --- a/runtime/interface.cpp +++ b/runtime/interface.cpp @@ -900,6 +900,7 @@ mixed v$_FILES __attribute__ ((weak)); mixed v$_COOKIE __attribute__ ((weak)); mixed v$_REQUEST __attribute__ ((weak)); mixed v$_ENV __attribute__ ((weak)); +mixed v$_SESSION __attribute__ ((weak)); mixed v$argc __attribute__ ((weak)); mixed v$argv __attribute__ ((weak)); @@ -1467,9 +1468,9 @@ static void reset_superglobals() { hard_reset_var(v$_GET, array()); hard_reset_var(v$_POST, array()); hard_reset_var(v$_FILES, array()); - hard_reset_var(v$_COOKIE, array()); hard_reset_var(v$_REQUEST, array()); hard_reset_var(v$_ENV, array()); + hard_reset_var(v$_COOKIE, array()); dl::leave_critical_section(); } diff --git a/runtime/interface.h b/runtime/interface.h index ee84f3c8fe..dda1dcca3b 100644 --- a/runtime/interface.h +++ b/runtime/interface.h @@ -151,6 +151,7 @@ extern mixed v$_FILES; extern mixed v$_COOKIE; extern mixed v$_REQUEST; extern mixed v$_ENV; +extern mixed v$_SESSION; const int32_t UPLOAD_ERR_OK = 0; const int32_t UPLOAD_ERR_INI_SIZE = 1; From 6b2f3a6ab35ebde33b6c036a1954b1b8ca6c2b2f Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 20 Mar 2024 19:58:25 +0300 Subject: [PATCH 02/56] Define sessions 1. Define session class. 2. Define the basic structure of the basic functions. 3. Write the abstract logic of reading and writing session files with the stream and serialize functions. --- runtime/sessions.cpp | 270 +++++++++++++++++++++++++++++++++++++++++++ runtime/sessions.h | 54 +++++++++ 2 files changed, 324 insertions(+) create mode 100644 runtime/sessions.cpp create mode 100644 runtime/sessions.h diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp new file mode 100644 index 0000000000..6921ea8c57 --- /dev/null +++ b/runtime/sessions.cpp @@ -0,0 +1,270 @@ +#include "runtime/sessions.h" +#include "runtime/serialize-functions.h" +#include "runtime/interface.h" +// #include "runtime/files.h" +// #include "runtime/critical_section.h" + + +/* +TO-DO: +- generate_session_id() +- send_cookies() +- session_start(): check the id for dangerous symbols +- f$session_start(): + - check whether headers were sent or not + - parse argument const array options + - read_and_close + - session_flush() +- f$session_destroy() +*/ + +namespace sessions { + +static const SM = vk::singleton::get(); + +SM.tempdir_path = string(getenv("TMPDIR")); +SM.sessions_path = SM.tempdir_path + string("/sessions/"); +if (!f$file_exists(SM.sessions_path)) { + f$mkdir(SM.sessions_path); +} + +static bool generate_session_id() { + // pass +} + +bool SessionManager::session_write() { + if (!session_open()) { + return false; + } + f$file_put_contents(handler, string("")); // f$ftruncate(handler, 0); + f$rewind(handler); + { // additional local scope for temprory variables tdata and tres + string tdata = f$serialize(v$_SESSION); + mixed tres = f$file_put_contents(handler, tdata); + if (tres.is_bool() || static_cast(tres.as_int()) != tdata.size()) { + php_warning(); + return false; + } + } + return true; +} + +bool SessionManager::session_read() { + if ((handler.is_null()) || (!session_open())) { + php_warning(); + return false; + } + { // additional local scope for temprory variable tdata + Optional tdata; + data = f$file_get_contents(handler); + if (data.is_false() or data.is_null()) { + return false; + } + v$_SESSION = f$unserialize(data.val()); + } + return true; +} + +bool SessionManager::session_open() { + if (id.is_null()) { + return false; + } + if (!handler.is_null()) { + session_close(); + } + + if (session_path.is_null()) { + // setting the session_path is only here => can be unchecked if it exists + session_path = sessions_path + id.val() + string("/"); + if (!f$is_dir(session_path)) { + f$mkdir(session_path); + } + session_path += id.val() + string(".sess"); + } + + { // additional local scope for temprory variable thandler + mixed thandler = f$fopen(session_path, string("r+")); + handler = (!thandler.is_bool()) ? thandler : NULL; + } + if (handler.is_null()) { + return false; + } + return true; +} + +bool SessionManager::session_close() { + if (handler.is_null()) { + return true; + } + + if (!f$fclose(handler)) { + php_warning(); + return false; + } + handler = NULL; + return true; +} + +static bool session_abort() { + if (SM.get_session_status()) { + SM.session_close(); + SM.set_session_status(0); + return true; + } + return false; +} + +static bool session_flush() { + // pass +} + +static bool send_cookies() { + // 1. check whether headers were sent or not + // pass: can return false here + + // 2. check session_name for deprecated symbols, if it's user supplied + // pass: can return false here + + // 3. encode session_name, if it's user supplied + // pass: can return false here + + // 4. set specific headers in the cookies + f$setcookie(/* some data here */); + return true; +} + +static bool session_reset_id() { + if (SM.get_session_id().is_null()) { + php_warning("Cannot set session ID - session ID is not initialized"); + return false; + } + + if (SM.get_send_cookie()) { + send_cookies(); // TO-DO + SM.set_send_cookie(0); + } + + return true; +} + +static bool session_initialize() { + SM.set_session_status(1); + + SM.session_open(); + if (SM.get_handler().is_null()) { + session_abort(); + php_warning(); + return false; + } + + if (SM.get_session_id().is_null()) { + SM.generate_session_id(); // TO-DO + if (SM.get_session_id().is_null()) { + session_abort(); + php_warning("Failed to create session ID: %s (path: %s)", SM.session_name.c_str(), SM.get_session_path().val().c_str()); + return false; + } + SM.set_send_cookie(1); + } + + session_reset_id(); + + if (!SM.session_read()) { + SM.session_abort(); + php_warning("Failed to read session data: %s (path: %s)", SM.session_name.c_str(), SM.get_session_path().val().c_str()); + return false; + } + return true; +} + +static void session_start() { + // 1. check status of the session + if (SM.get_session_status()) { + if (SM.get_session_path().has_value()) { + php_warning("Ignoring session_start() because a session is already active (started from %s)", SM.get_session_path().val().c_str()); + } else { + php_warning("Ignoring session_start() because a session is already active"); + } + return false; + } + + SM.set_send_cookie(1); + + if (SM.get_session_name().is_null()) { + SM.set_session_name("PHPSESSID"); // or "KPHPSESSID" + } + + // 2. check id of session + if (!SM.get_session_id().is_null()) { + // 4.1 try to get an id of session via it's name from _COOKIE + mixed pid = (v$_COOKIE.has_key(SM.session_name)) ? v$_COOKIE.get_value(SM.session_name) : NULL; + if (!pid.is_string()) { + pid = NULL; + } else { + SM.set_send_cookie(0); + } + SM.set_session_id(pid); + } + + // 5. check the id for dangerous symbols + // pass + + // 6. try to initialize the session + if (!session_initialize()) { + SM.set_session_status(0); + SM.set_session_id(NULL); + return false; + } + return true; +} + +} // namespace sessions + +bool f$session_start(/*const array &options*/) { + // 1. check status of session + if (sessions::SM.get_session_status()) { + if (sessions::SM.get_session_path().has_value()) { + php_warning("Ignoring session_start() because a session is already active (started from %s)", sessions::SM.get_session_path().val().c_str()); + } else { + php_warning("Ignoring session_start() because a session is already active"); + } + return true; + } + + // 2. check whether headers were sent or not + // for this kphp must have the headers_sent() function + + // bool read_and_close = false; + + // 3. parse the options arg and set it + // if (!options.empty()) { + // for (auto it = options.begin(); it != options.end(); ++it) { + // if (it.get_key().to_string() == "read_and_close") { + // read_and_close = true; + // } else { + // // 3.1 get the value and modify the session header with the same key + // // store to the buffer data + // // pass + // } + // } + // } + + sessions::session_start(); + + // 4. check the status of the session + if (!sessions::MS.get_session_status()) { + // 4.1 clear cache of session variables + // pass + php_warning(); + return false; + } + + // 5. check for read_and_close + // if (read_and_close) { + // // session_flush() + // // pass + // } + + return true; +} + diff --git a/runtime/sessions.h b/runtime/sessions.h new file mode 100644 index 0000000000..fdf99fce1e --- /dev/null +++ b/runtime/sessions.h @@ -0,0 +1,54 @@ +#pragma once + +#include "runtime/kphp_core.h" +#include "runtime/streams.h" + +namespace sessions { + +class SessionManager : vk::not_copyable { +public: + bool session_open(); + bool session_close(); + bool session_read(); + bool session_write(); + bool session_delete(); + + const bool &set_session_status(const bool &status) const noexcept { return session_status = status; } + const bool &get_session_status() const noexcept { return session_status; } + const Optional &set_session_path(const bool &path) const noexcept { return session_path = path; } + const Optional &get_session_path() const noexcept { return session_path; } + const Optional &set_session_id(const string &sid) const noexcept { return id = sid; } + const Optional &get_session_id() const noexcept { return id; } + const Optional &set_send_cookie(const bool &val) const noexcept { return send_cookie = val; } + const Optional &get_send_cookie() const noexcept { return send_cookie; } + const Optional &set_session_name(const string &val) const noexcept { return session_name = val; } + const Optional &get_session_name() const noexcept { return session_name; } + + const Optional &set_handler(const Stream &stream) const noexcept {return handler = stream; } + const Optional &get_handler() const noexcept {return handler; } + +private: + SessionManager() = default; + + Optional id{NULL}; + bool session_status{0}; + bool send_cookie{0}; + Optional session_path{NULL}; + Optional session_name{NULL}; // by default PHPSESSID (key for searching in the cookies) + + const string tempdir_path; // path to the /tmp + const string sessions_path; // path to the dir with existing sessions + + Optional handler{NULL}; + + friend class vk::singleton; +}; + +} // namespace sessions + +bool f$session_start(); +bool f$session_abort(); +bool f$session_commit(); +bool f$session_write_close(); +int64_t f$session_status(); +Optional f$session_create_id(const string &prefix); From 362fbd1e23441bbd01931f9628d9852a75700eb1 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 27 Mar 2024 17:26:24 +0300 Subject: [PATCH 03/56] Add sessions to compilation target --- runtime/runtime.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/runtime.cmake b/runtime/runtime.cmake index 7bfc8d802f..cfa8b1b0f2 100644 --- a/runtime/runtime.cmake +++ b/runtime/runtime.cmake @@ -123,7 +123,8 @@ prepend(KPHP_RUNTIME_SOURCES ${BASE_DIR}/runtime/ vkext_stats.cpp ffi.cpp zlib.cpp - zstd.cpp) + zstd.cpp + sessions.cpp) set_source_files_properties( ${BASE_DIR}/server/php-engine.cpp From 14fa55935797ff4e324ff4760c60a4639ad2d9c3 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 27 Mar 2024 17:27:12 +0300 Subject: [PATCH 04/56] Stage non-working version of sessions --- builtin-functions/_functions.txt | 8 + runtime/interface.cpp | 2 + runtime/sessions.cpp | 358 ++++++++++++++++++++++--------- runtime/sessions.h | 69 ++++-- 4 files changed, 318 insertions(+), 119 deletions(-) diff --git a/builtin-functions/_functions.txt b/builtin-functions/_functions.txt index 42875a11f1..b4ee7d1fde 100644 --- a/builtin-functions/_functions.txt +++ b/builtin-functions/_functions.txt @@ -772,6 +772,14 @@ function mb_strtolower ($str ::: string, $encoding ::: string = "cp1251") ::: st function mb_strtoupper ($str ::: string, $encoding ::: string = "cp1251") ::: string; function mb_substr ($str ::: string, $start ::: int, $length ::: mixed = PHP_INT_MAX, $encoding ::: string = "cp1251") ::: string; +function session_start(?mixed $options = null) ::: bool; +function session_abort() ::: bool; +function session_commit() ::: bool; +function session_write_close() ::: bool; +function session_gc() ::: bool; +function session_status() ::: bool; +function session_destroy() ::: bool; + define('PHP_ROUND_HALF_UP', 123423141); define('PHP_ROUND_HALF_DOWN', 123423144); define('PHP_ROUND_HALF_EVEN', 123423145); diff --git a/runtime/interface.cpp b/runtime/interface.cpp index 5686a2ffe2..1c5e9cb465 100644 --- a/runtime/interface.cpp +++ b/runtime/interface.cpp @@ -56,6 +56,7 @@ #include "runtime/udp.h" #include "runtime/url.h" #include "runtime/zlib.h" +// #include "runtime/sessions.h" #include "server/curl-adaptor.h" #include "server/database-drivers/adaptor.h" #include "server/database-drivers/mysql/mysql.h" @@ -1471,6 +1472,7 @@ static void reset_superglobals() { hard_reset_var(v$_REQUEST, array()); hard_reset_var(v$_ENV, array()); hard_reset_var(v$_COOKIE, array()); + hard_reset_var(v$_SESSION, mixed(NULL)); // Is this correct? dl::leave_critical_section(); } diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 6921ea8c57..70951f06db 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -1,48 +1,79 @@ +#include +#include + #include "runtime/sessions.h" #include "runtime/serialize-functions.h" #include "runtime/interface.h" -// #include "runtime/files.h" +#include "runtime/streams.h" +#include "runtime/url.h" +#include "runtime/files.h" +#include "runtime/misc.h" // #include "runtime/critical_section.h" - -/* -TO-DO: -- generate_session_id() -- send_cookies() -- session_start(): check the id for dangerous symbols -- f$session_start(): - - check whether headers were sent or not - - parse argument const array options - - read_and_close - - session_flush() -- f$session_destroy() -*/ - namespace sessions { -static const SM = vk::singleton::get(); +SessionManager::SessionManager() { + tempdir_path = string(getenv("TMPDIR")); + sessions_path = string(tempdir_path).append("sessions/"); + if (!f$file_exists(sessions_path)) { + f$mkdir(sessions_path); + } +} + +static SessionManager &SM = vk::singleton::get(); -SM.tempdir_path = string(getenv("TMPDIR")); -SM.sessions_path = SM.tempdir_path + string("/sessions/"); -if (!f$file_exists(SM.sessions_path)) { - f$mkdir(SM.sessions_path); +static bool session_valid_id(const string &id) { + if (id.empty()) { + return false; + } + bool result = true; + for (auto i = (string("sess_").size()); i < id.size(); ++i) { + if (!((id[i] >= 'a' && id[i] <= 'z') + || (id[i] >= 'A' && id[i] <= 'Z') + || (id[i] >= '0' && id[i] <= '9') + || (id[i] == ',') + || (id[i] == '-'))) { + result = false; + break; + } + } + return result; } static bool generate_session_id() { - // pass + if (!SM.get_session_status()) { + return false; + } + string id = f$uniqid(string("sess_")); + + if (!session_valid_id(id)) { + php_warning("Failed to create new ID\n"); + return false; + } + SM.set_session_id(id); + return true; +} + +void SessionManager::session_reset_vars() { + handler = NULL; + id = false; + session_status = send_cookie = 0; + cookie_secure = cookie_httponly = 0; + cookie_lifetime = 0; + session_path = session_name = cookie_domain = false; } bool SessionManager::session_write() { if (!session_open()) { return false; } - f$file_put_contents(handler, string("")); // f$ftruncate(handler, 0); + f$file_put_contents(handler.to_string(), string("")); // f$ftruncate(handler, 0); f$rewind(handler); { // additional local scope for temprory variables tdata and tres string tdata = f$serialize(v$_SESSION); - mixed tres = f$file_put_contents(handler, tdata); + mixed tres = f$file_put_contents(handler.to_string(), tdata); if (tres.is_bool() || static_cast(tres.as_int()) != tdata.size()) { - php_warning(); + // php_warning(); return false; } } @@ -51,39 +82,42 @@ bool SessionManager::session_write() { bool SessionManager::session_read() { if ((handler.is_null()) || (!session_open())) { - php_warning(); + // php_warning(); return false; } { // additional local scope for temprory variable tdata Optional tdata; - data = f$file_get_contents(handler); - if (data.is_false() or data.is_null()) { + tdata = f$file_get_contents(handler.to_string()); + if (tdata.is_false()) { return false; } - v$_SESSION = f$unserialize(data.val()); + v$_SESSION = f$unserialize(tdata.val()); // TO-DO: check } + fprintf(stdout, "successfully read the session data with id %s\n", SM.get_session_id().val().c_str()); return true; } bool SessionManager::session_open() { - if (id.is_null()) { + if (id.is_false()) { return false; } if (!handler.is_null()) { session_close(); } - if (session_path.is_null()) { - // setting the session_path is only here => can be unchecked if it exists - session_path = sessions_path + id.val() + string("/"); - if (!f$is_dir(session_path)) { - f$mkdir(session_path); - } - session_path += id.val() + string(".sess"); + if (session_path.is_false()) { + // setting the session_path is only here + session_path = sessions_path; + session_path.val().append(id.val()); + session_path.val().append(".sess"); } + if (!f$file_exists(session_path.val())) { + f$fclose(f$fopen(session_path.val(), string("w+"))); + } + { // additional local scope for temprory variable thandler - mixed thandler = f$fopen(session_path, string("r+")); + mixed thandler = f$fopen(session_path.val(), string("r+")); handler = (!thandler.is_bool()) ? thandler : NULL; } if (handler.is_null()) { @@ -92,16 +126,76 @@ bool SessionManager::session_open() { return true; } -bool SessionManager::session_close() { +static bool session_destroy(const string &filepath) { + + Optional ctime = f$filectime(filepath); + if (ctime.is_false()) { + php_warning("Failed to get metadata of file %s\n", filepath.c_str()); + } + + // Stream thandler = f$fopen(filepath, string("r")); + // if (!thandler) { + // php_warning("Failed to open file %s\n", filepath.c_str()); + // return false; + // } + + Optional sdata = f$file_get_contents(filepath); + if (sdata.is_false()) { + php_warning("Failed to read file %s\n", filepath.c_str()); + return false; + } + array tdata = f$unserialize(sdata.val()).to_array(); + int lifetime = 0; + if (tdata.has_key(string("gc_maxlifetime"))) { + lifetime = tdata.get_value(string("gc_maxlifetime")).to_int(); + } + if (ctime < lifetime) { + // f$fclose(thandler); + return false; + } + // f$fclose(thandler); + return f$unlink(filepath); +} + +static bool session_gc() { + Optional> sfiles = f$scandir(SM.get_sessions_path()); + if (sfiles.is_false()) { + php_warning("Failed to scan sessions directory %s\n", SM.get_sessions_path().c_str()); + return false; + } + fprintf(stdout, "result of scandir is:\n%s\n", f$serialize(sfiles.val()).c_str()); + auto nsfiles = sfiles.val().count(); + int n = 0; + for (auto sfile = sfiles.val().cbegin(); sfile != sfiles.val().cend(); ++sfile) { + string val = sfile.get_value().to_string(); + if (val == string(".") or val == string("..")) { + continue; + } + if (session_destroy(val)) { + ++n; + } + } + if (n != nsfiles) { + php_warning("Failed to delete all files in sessions dir %s\n", SM.get_sessions_path().c_str()); + return false; + } + return true; +} + +bool SessionManager::session_close(bool immediate) { if (handler.is_null()) { return true; } if (!f$fclose(handler)) { - php_warning(); + // php_warning(); return false; } - handler = NULL; + session_reset_vars(); + + if (immediate or rand() % 100 > 75) { + session_gc(); + } return true; } @@ -114,33 +208,50 @@ static bool session_abort() { return false; } -static bool session_flush() { - // pass +static bool session_flush(bool write = false) { + if (!SM.get_session_status()) { + return false; + } + bool result = true; + if (write && !SM.session_write()) { + php_warning("Failed to write session data %s\n", SM.get_session_path().val().c_str()); + result = false; + } + + SM.set_session_status(0); + SM.session_close(); + return result; } static bool send_cookies() { // 1. check whether headers were sent or not - // pass: can return false here + // pass: need headers_sent() // 2. check session_name for deprecated symbols, if it's user supplied - // pass: can return false here + if (strpbrk(SM.get_session_name().val().c_str(), "=,;.[ \t\r\n\013\014") != NULL) { + php_warning("session.name cannot contain any of the following '=,;.[ \\t\\r\\n\\013\\014'"); + return false; + } // 3. encode session_name, if it's user supplied - // pass: can return false here - - // 4. set specific headers in the cookies - f$setcookie(/* some data here */); + int expire = SM.get_session_lifetime(); + if (expire > 0) { + expire += std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + string domain = !SM.get_cookie_domain().is_false() ? SM.get_cookie_domain().val() : string(""); + f$setcookie(SM.get_session_name().val(), f$urlencode(SM.get_session_id().val()), expire, string("/"), domain, SM.get_cookie_secure(), SM.get_cookie_httponly()); + fprintf(stdout, "successfully sent cookies for id %s\n", SM.get_session_id().val().c_str()); return true; } static bool session_reset_id() { - if (SM.get_session_id().is_null()) { + if (SM.get_session_id().is_false()) { php_warning("Cannot set session ID - session ID is not initialized"); return false; } if (SM.get_send_cookie()) { - send_cookies(); // TO-DO + send_cookies(); SM.set_send_cookie(0); } @@ -150,37 +261,38 @@ static bool session_reset_id() { static bool session_initialize() { SM.set_session_status(1); - SM.session_open(); - if (SM.get_handler().is_null()) { - session_abort(); - php_warning(); - return false; - } - - if (SM.get_session_id().is_null()) { - SM.generate_session_id(); // TO-DO - if (SM.get_session_id().is_null()) { + if (SM.get_session_id().is_false()) { + generate_session_id(); + if (SM.get_session_id().is_false()) { session_abort(); - php_warning("Failed to create session ID: %s (path: %s)", SM.session_name.c_str(), SM.get_session_path().val().c_str()); + php_warning("Failed to create session ID: %s (path: %s)", SM.get_session_name().val().c_str(), SM.get_session_path().val().c_str()); return false; } SM.set_send_cookie(1); } + + SM.session_open(); + if (SM.get_handler().is_null()) { + session_abort(); + // php_warning(); + return false; + } session_reset_id(); if (!SM.session_read()) { - SM.session_abort(); - php_warning("Failed to read session data: %s (path: %s)", SM.session_name.c_str(), SM.get_session_path().val().c_str()); + session_abort(); + php_warning("Failed to read session data: %s (path: %s)\n", SM.get_session_name().val().c_str(), SM.get_session_path().val().c_str()); return false; } + return true; } -static void session_start() { +static bool session_start() { // 1. check status of the session if (SM.get_session_status()) { - if (SM.get_session_path().has_value()) { + if (SM.get_session_path().is_false()) { php_warning("Ignoring session_start() because a session is already active (started from %s)", SM.get_session_path().val().c_str()); } else { php_warning("Ignoring session_start() because a session is already active"); @@ -190,29 +302,34 @@ static void session_start() { SM.set_send_cookie(1); - if (SM.get_session_name().is_null()) { - SM.set_session_name("PHPSESSID"); // or "KPHPSESSID" + if (SM.get_session_name().is_false()) { + SM.set_session_name(string("PHPSESSID")); } + fprintf(stdout, "session name is: %s\n", SM.get_session_name().val().c_str()); // 2. check id of session - if (!SM.get_session_id().is_null()) { + if (SM.get_session_id().is_false()) { // 4.1 try to get an id of session via it's name from _COOKIE - mixed pid = (v$_COOKIE.has_key(SM.session_name)) ? v$_COOKIE.get_value(SM.session_name) : NULL; - if (!pid.is_string()) { - pid = NULL; - } else { + Optional pid{false}; + if (v$_COOKIE.as_array().has_key(SM.get_session_name().val())) { + pid = v$_COOKIE.get_value(SM.get_session_name().val()).to_string(); + fprintf(stdout, "found session id in cookies: %s\n", pid.val().c_str()); + } + if (!pid.is_false()) { SM.set_send_cookie(0); } SM.set_session_id(pid); } // 5. check the id for dangerous symbols - // pass + if (!SM.get_session_id().is_false() && strpbrk(SM.get_session_id().val().c_str(), "\r\n\t <>'\"\\")) { + SM.set_session_id(false); + } // 6. try to initialize the session if (!session_initialize()) { SM.set_session_status(0); - SM.set_session_id(NULL); + SM.set_session_id(false); return false; } return true; @@ -220,10 +337,10 @@ static void session_start() { } // namespace sessions -bool f$session_start(/*const array &options*/) { +bool f$session_start(const array &options) { // 1. check status of session if (sessions::SM.get_session_status()) { - if (sessions::SM.get_session_path().has_value()) { + if (sessions::SM.get_session_path().is_false()) { php_warning("Ignoring session_start() because a session is already active (started from %s)", sessions::SM.get_session_path().val().c_str()); } else { php_warning("Ignoring session_start() because a session is already active"); @@ -232,39 +349,86 @@ bool f$session_start(/*const array &options*/) { } // 2. check whether headers were sent or not - // for this kphp must have the headers_sent() function + // need headers_sent() + // pass - // bool read_and_close = false; + bool read_and_close = false; // 3. parse the options arg and set it - // if (!options.empty()) { - // for (auto it = options.begin(); it != options.end(); ++it) { - // if (it.get_key().to_string() == "read_and_close") { - // read_and_close = true; - // } else { - // // 3.1 get the value and modify the session header with the same key - // // store to the buffer data - // // pass - // } - // } - // } - + if (!options.empty()) { + for (auto it = options.begin(); it != options.end(); ++it) { + string tkey = it.get_key().to_string(); + if (tkey == string("read_and_close")) { + read_and_close = it.get_value().to_bool(); + } else if (tkey == string("name")) { + sessions::SM.set_session_name(it.get_value().to_string()); + } else if (tkey == string("gc_maxlifetime")) { + sessions::SM.set_session_lifetime(it.get_value().to_int()); + } else if (tkey == string("cookie_path")) { + sessions::SM.set_session_path(it.get_value().to_string()); + } else if (tkey == string("cookie_lifetime")) { + sessions::SM.set_cookie_lifetime(it.get_value().to_int()); + } else if (tkey == string("cookie_domain")) { + sessions::SM.set_cookie_domain(it.get_value().to_string()); + } else if (tkey == string("cookie_secure")) { + sessions::SM.set_cookie_secure(it.get_value().to_bool()); + } else if (tkey == string("cookie_httponly")) { + sessions::SM.set_cookie_httponly(it.get_value().to_bool()); + } + } + } + fprintf(stdout, "Before session_start()\n"); sessions::session_start(); + fprintf(stdout, "After session_start()\n"); // 4. check the status of the session - if (!sessions::MS.get_session_status()) { + if (!sessions::SM.get_session_status()) { // 4.1 clear cache of session variables - // pass - php_warning(); + v$_SESSION = NULL; + // php_warning(); return false; } // 5. check for read_and_close - // if (read_and_close) { - // // session_flush() - // // pass - // } + if (read_and_close) { + sessions::session_flush(); + } return true; } +bool f$session_destroy() { + if (!sessions::SM.get_session_status()) { + php_warning("Trying to destroy uninitialized session"); + return false; + } + + if (sessions::SM.get_session_path().has_value()) { + return sessions::session_destroy(sessions::SM.get_session_path().val()); + } + sessions::SM.session_close(); + return false; +} + +bool f$session_abort() { + if (!sessions::SM.get_session_status()) { + return false; + } + return sessions::session_abort(); +} + +int64_t f$session_status() { + return static_cast(sessions::SM.get_session_status()) + 1; +} + +bool f$session_write_close() { + if (!sessions::SM.get_session_status()) { + return false; + } + return sessions::session_flush(1); +} + +bool $session_commit() { + return f$session_write_close(); +} + diff --git a/runtime/sessions.h b/runtime/sessions.h index fdf99fce1e..e66a5d0c5e 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -1,53 +1,78 @@ #pragma once #include "runtime/kphp_core.h" -#include "runtime/streams.h" +#include "common/mixin/not_copyable.h" +#include "common/smart_ptrs/singleton.h" namespace sessions { +using Stream = mixed; + class SessionManager : vk::not_copyable { public: bool session_open(); - bool session_close(); + bool session_close(bool immediate = false); bool session_read(); bool session_write(); bool session_delete(); - const bool &set_session_status(const bool &status) const noexcept { return session_status = status; } - const bool &get_session_status() const noexcept { return session_status; } - const Optional &set_session_path(const bool &path) const noexcept { return session_path = path; } - const Optional &get_session_path() const noexcept { return session_path; } - const Optional &set_session_id(const string &sid) const noexcept { return id = sid; } - const Optional &get_session_id() const noexcept { return id; } - const Optional &set_send_cookie(const bool &val) const noexcept { return send_cookie = val; } - const Optional &get_send_cookie() const noexcept { return send_cookie; } - const Optional &set_session_name(const string &val) const noexcept { return session_name = val; } - const Optional &get_session_name() const noexcept { return session_name; } + void session_reset_vars(); + + void set_session_status(const bool &status) noexcept { session_status = status; } + void set_session_path(const string &path) noexcept { session_path = path; } + void set_session_id(const Optional &sid) noexcept { id = sid; } + void set_send_cookie(const bool &val) noexcept { send_cookie = val; } + void set_session_name(const string &val) noexcept { session_name = val; } + void set_session_lifetime(const int &val) noexcept { session_lifetime = val; } + void set_handler(const Stream &stream) noexcept { handler = stream; } - const Optional &set_handler(const Stream &stream) const noexcept {return handler = stream; } - const Optional &get_handler() const noexcept {return handler; } + void set_cookie_domain(const string &val) noexcept { cookie_domain = val; } + void set_cookie_lifetime(const int &val) noexcept { cookie_lifetime = val; } + void set_cookie_secure(const bool &val) noexcept { cookie_secure = val; } + void set_cookie_httponly(const bool &val) noexcept { cookie_httponly = val; } + + bool get_session_status() noexcept { return session_status; } + Optional get_session_path() noexcept { return session_path; } + Optional get_session_id() noexcept { return id; } + bool get_send_cookie() noexcept { return send_cookie; } + Optional get_session_name() noexcept { return session_name; } + int get_session_lifetime() noexcept { return session_lifetime; } + Stream get_handler() noexcept {return handler; } + + string get_sessions_path() noexcept { return sessions_path; } + Optional get_cookie_domain() noexcept { return cookie_domain; } + int get_cookie_lifetime() noexcept { return cookie_lifetime; } + bool get_cookie_secure() noexcept { return cookie_secure; } + bool get_cookie_httponly() noexcept { return cookie_httponly; } private: - SessionManager() = default; + SessionManager(); - Optional id{NULL}; + Optional id{false}; bool session_status{0}; bool send_cookie{0}; - Optional session_path{NULL}; - Optional session_name{NULL}; // by default PHPSESSID (key for searching in the cookies) + Optional session_path{false}; + Optional session_name{false}; // by default PHPSESSID (key for searching in the cookies) + int session_lifetime{1440}; + + int cookie_lifetime{0}; + Optional cookie_domain{false}; + bool cookie_secure{0}; + bool cookie_httponly{0}; - const string tempdir_path; // path to the /tmp - const string sessions_path; // path to the dir with existing sessions + string tempdir_path; // path to the /tmp + string sessions_path; // path to the dir with existing sessions - Optional handler{NULL}; + Stream handler{NULL}; friend class vk::singleton; }; } // namespace sessions -bool f$session_start(); +bool f$session_start(const array &options = array()); bool f$session_abort(); +bool f$session_destroy(); bool f$session_commit(); bool f$session_write_close(); int64_t f$session_status(); From 0774419dc688d000b0f67b2c5608aaf8a7283a3b Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Mon, 1 Apr 2024 12:23:52 +0300 Subject: [PATCH 05/56] Add new global array for session handler --- compiler/data/var-data.cpp | 2 +- compiler/vertex-util.cpp | 1 + runtime/interface.cpp | 5 +++-- runtime/interface.h | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/data/var-data.cpp b/compiler/data/var-data.cpp index 148236076a..db9553e4e7 100644 --- a/compiler/data/var-data.cpp +++ b/compiler/data/var-data.cpp @@ -35,7 +35,7 @@ const ClassMemberInstanceField *VarData::as_class_instance_field() const { // TODO Dirty HACK, should be removed bool VarData::does_name_eq_any_builtin_global(const std::string &name) { static const std::unordered_set names = { - "_SERVER", "_GET", "_POST", "_FILES", "_COOKIE", "_REQUEST", "_ENV", "_SESSION", "argc", "argv", + "_SERVER", "_GET", "_POST", "_FILES", "_COOKIE", "_REQUEST", "_ENV", "_SESSION", "_KPHPSESSARR", "argc", "argv", "MC", "MC_True", "config", "Durov", "FullMCTime", "KPHP_MC_WRITE_STAT_PROBABILITY", "d$PHP_SAPI"}; return names.find(name) != names.end(); diff --git a/compiler/vertex-util.cpp b/compiler/vertex-util.cpp index 0a1717a16f..595deea0bd 100644 --- a/compiler/vertex-util.cpp +++ b/compiler/vertex-util.cpp @@ -126,6 +126,7 @@ bool VertexUtil::is_superglobal(const std::string &s) { "_REQUEST", "_ENV", "_SESSION" + "_KPHPSESSARR" }; return vk::contains(names, s); } diff --git a/runtime/interface.cpp b/runtime/interface.cpp index 1c5e9cb465..c6dc2dacc5 100644 --- a/runtime/interface.cpp +++ b/runtime/interface.cpp @@ -56,7 +56,6 @@ #include "runtime/udp.h" #include "runtime/url.h" #include "runtime/zlib.h" -// #include "runtime/sessions.h" #include "server/curl-adaptor.h" #include "server/database-drivers/adaptor.h" #include "server/database-drivers/mysql/mysql.h" @@ -902,6 +901,7 @@ mixed v$_COOKIE __attribute__ ((weak)); mixed v$_REQUEST __attribute__ ((weak)); mixed v$_ENV __attribute__ ((weak)); mixed v$_SESSION __attribute__ ((weak)); +mixed v$_KPHPSESSARR __attribute__ ((weak)); mixed v$argc __attribute__ ((weak)); mixed v$argv __attribute__ ((weak)); @@ -1472,7 +1472,8 @@ static void reset_superglobals() { hard_reset_var(v$_REQUEST, array()); hard_reset_var(v$_ENV, array()); hard_reset_var(v$_COOKIE, array()); - hard_reset_var(v$_SESSION, mixed(NULL)); // Is this correct? + hard_reset_var(v$_SESSION, array()); + hard_reset_var(v$_KPHPSESSARR, array()); dl::leave_critical_section(); } diff --git a/runtime/interface.h b/runtime/interface.h index dda1dcca3b..d5b50f3f54 100644 --- a/runtime/interface.h +++ b/runtime/interface.h @@ -152,6 +152,7 @@ extern mixed v$_COOKIE; extern mixed v$_REQUEST; extern mixed v$_ENV; extern mixed v$_SESSION; +extern mixed v$_KPHPSESSARR; const int32_t UPLOAD_ERR_OK = 0; const int32_t UPLOAD_ERR_INI_SIZE = 1; From efa217d08922ef2efa0e16cc43fe08eece46509e Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Mon, 1 Apr 2024 12:24:25 +0300 Subject: [PATCH 06/56] Change the session_start() arguments --- builtin-functions/_functions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-functions/_functions.txt b/builtin-functions/_functions.txt index b4ee7d1fde..f1cc67c6cc 100644 --- a/builtin-functions/_functions.txt +++ b/builtin-functions/_functions.txt @@ -772,7 +772,7 @@ function mb_strtolower ($str ::: string, $encoding ::: string = "cp1251") ::: st function mb_strtoupper ($str ::: string, $encoding ::: string = "cp1251") ::: string; function mb_substr ($str ::: string, $start ::: int, $length ::: mixed = PHP_INT_MAX, $encoding ::: string = "cp1251") ::: string; -function session_start(?mixed $options = null) ::: bool; +function session_start($options ::: mixed = array()) ::: bool; function session_abort() ::: bool; function session_commit() ::: bool; function session_write_close() ::: bool; From c0bf68467891e87c341e6fddd706e346e8f1e310 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Mon, 1 Apr 2024 12:25:53 +0300 Subject: [PATCH 07/56] Implement basic functions of sessions: session_start, session_read --- runtime/sessions.cpp | 507 ++++++++++++++++++------------------------- runtime/sessions.h | 76 +------ 2 files changed, 209 insertions(+), 374 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 70951f06db..c45e4dabfa 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -2,30 +2,98 @@ #include #include "runtime/sessions.h" +#include "runtime/files.h" #include "runtime/serialize-functions.h" +#include "runtime/misc.h" +#include "common/wrappers/to_array.h" #include "runtime/interface.h" -#include "runtime/streams.h" #include "runtime/url.h" -#include "runtime/files.h" -#include "runtime/misc.h" -// #include "runtime/critical_section.h" namespace sessions { -SessionManager::SessionManager() { - tempdir_path = string(getenv("TMPDIR")); - sessions_path = string(tempdir_path).append("sessions/"); - if (!f$file_exists(sessions_path)) { - f$mkdir(sessions_path); +static mixed get_sparam(const char *key) noexcept; +static mixed get_sparam(const string &key) noexcept; +static void set_sparam(const char *key, const mixed &value) noexcept; +static void set_sparam(const string &key, const mixed &value) noexcept; +static void reset_sparams() noexcept; +static void initialize_sparams(const array &options) noexcept; + +static bool session_start(); +static bool session_initialize(); +static bool session_generate_id(); +static bool session_valid_id(const string &id); +static bool session_abort(); +static bool session_reset_id(); +static bool session_send_cookie(); +// static bool session_flush(); + +static bool session_open(); +static bool session_read(); +// static bool session_write(); +static void session_close(); + +static void initialize_sparams(const array &options) noexcept { + // TO-DO: reconsider it + const auto skeys = vk::to_array>({ + {"read_and_close", false}, + {"save_path", string(getenv("TMPDIR")).append("sessions/")}, + {"name", string("PHPSESSID")}, + {"gc_maxlifetime", 1440}, + {"cookie_path", string("/")}, + {"cookie_lifetime", 0}, + {"cookie_domain", string("")}, + {"cookie_secure", false}, + {"cookie_httponly", false} + }); + + reset_sparams(); + + for (const auto& it : skeys) { + if (options.isset(string(it.first))) { + set_sparam(it.first, options.get_value(string(it.first))); + continue; + } + set_sparam(it.first, mixed(it.second)); + } +} + +static void print_sparams() noexcept { + fprintf(stdout, "\nKPHPSESSARR is:\n"); + for (auto it = v$_KPHPSESSARR.as_array().begin(); it != v$_KPHPSESSARR.as_array().end(); ++it) { + fprintf(stdout, "%s : %s\n", it.get_key().to_string().c_str(), it.get_value().to_string().c_str()); + } + + fprintf(stdout, "\n%s\n", f$serialize(v$_KPHPSESSARR.as_array()).c_str()); +} + +static void reset_sparams() noexcept { + v$_KPHPSESSARR = array(); +} + +static mixed get_sparam(const char *key) noexcept { + return get_sparam(string(key)); +} + +static mixed get_sparam(const string &key) noexcept { + if (!v$_KPHPSESSARR.as_array().isset(key)) { + return false; } + return v$_KPHPSESSARR.as_array().get_value(key); } -static SessionManager &SM = vk::singleton::get(); +static void set_sparam(const char *key, const mixed &value) noexcept { + set_sparam(string(key), value); +} + +static void set_sparam(const string &key, const mixed &value) noexcept { + v$_KPHPSESSARR.as_array().emplace_value(key, value); +} static bool session_valid_id(const string &id) { if (id.empty()) { return false; } + bool result = true; for (auto i = (string("sess_").size()); i < id.size(); ++i) { if (!((id[i] >= 'a' && id[i] <= 'z') @@ -40,395 +108,234 @@ static bool session_valid_id(const string &id) { return result; } -static bool generate_session_id() { - if (!SM.get_session_status()) { - return false; - } +static bool session_generate_id() { string id = f$uniqid(string("sess_")); - if (!session_valid_id(id)) { php_warning("Failed to create new ID\n"); return false; } - SM.set_session_id(id); + set_sparam("session_id", id); return true; } -void SessionManager::session_reset_vars() { - handler = NULL; - id = false; - session_status = send_cookie = 0; - cookie_secure = cookie_httponly = 0; - cookie_lifetime = 0; - session_path = session_name = cookie_domain = false; -} - -bool SessionManager::session_write() { - if (!session_open()) { - return false; - } - f$file_put_contents(handler.to_string(), string("")); // f$ftruncate(handler, 0); - f$rewind(handler); - { // additional local scope for temprory variables tdata and tres - string tdata = f$serialize(v$_SESSION); - mixed tres = f$file_put_contents(handler.to_string(), tdata); - if (tres.is_bool() || static_cast(tres.as_int()) != tdata.size()) { - // php_warning(); - return false; - } +static bool session_abort() { + if (get_sparam("session_status").to_bool()) { + session_close(); + set_sparam("session_status", false); + return true; } - return true; + return false; } -bool SessionManager::session_read() { - if ((handler.is_null()) || (!session_open())) { - // php_warning(); - return false; +static bool session_open() { + if (get_sparam("handler").to_bool()) { + /* + if we close the file for reopening it, + the other worker may open it faster and the current process will stop + */ + return true; } - { // additional local scope for temprory variable tdata - Optional tdata; - tdata = f$file_get_contents(handler.to_string()); - if (tdata.is_false()) { - return false; - } - v$_SESSION = f$unserialize(tdata.val()); // TO-DO: check + + if (!f$file_exists(get_sparam("save_path").to_string())) { + f$mkdir(get_sparam("save_path").to_string()); + fprintf(stdout, "session_open(): successfully created dir: %s\n", get_sparam("save_path").to_string().c_str()); } - fprintf(stdout, "successfully read the session data with id %s\n", SM.get_session_id().val().c_str()); - return true; -} -bool SessionManager::session_open() { - if (id.is_false()) { + set_sparam("file_path", string(get_sparam("save_path").to_string()).append(get_sparam("session_id").to_string())); + set_sparam("handler", open_safe(get_sparam("file_path").to_string().c_str(), O_RDWR | O_CREAT, 0777)); + + if (get_sparam("handler").to_int() < 0) { + php_warning("Failed to open the file %s", get_sparam("file_path").to_string().c_str()); return false; } - if (!handler.is_null()) { - session_close(); - } + fprintf(stdout, "session_open(): successfully opened file: handler %lld, path %s\n", get_sparam("handler").to_int(), get_sparam("file_path").to_string().c_str()); - if (session_path.is_false()) { - // setting the session_path is only here - session_path = sessions_path; - session_path.val().append(id.val()); - session_path.val().append(".sess"); + if (flock(get_sparam("handler").to_int(), LOCK_EX) < 0) { + php_warning("Failed to lock the file %s", get_sparam("file_path").to_string().c_str()); + return false; } - if (!f$file_exists(session_path.val())) { - f$fclose(f$fopen(session_path.val(), string("w+"))); - } + fprintf(stdout, "session_open(): successfully locked file: handler %lld, path %s\n", get_sparam("handler").to_int(), get_sparam("file_path").to_string().c_str()); - { // additional local scope for temprory variable thandler - mixed thandler = f$fopen(session_path.val(), string("r+")); - handler = (!thandler.is_bool()) ? thandler : NULL; - } - if (handler.is_null()) { - return false; - } return true; } -static bool session_destroy(const string &filepath) { - - Optional ctime = f$filectime(filepath); - if (ctime.is_false()) { - php_warning("Failed to get metadata of file %s\n", filepath.c_str()); - } - - // Stream thandler = f$fopen(filepath, string("r")); - // if (!thandler) { - // php_warning("Failed to open file %s\n", filepath.c_str()); - // return false; - // } - - Optional sdata = f$file_get_contents(filepath); - if (sdata.is_false()) { - php_warning("Failed to read file %s\n", filepath.c_str()); - return false; - } - array tdata = f$unserialize(sdata.val()).to_array(); - int lifetime = 0; - if (tdata.has_key(string("gc_maxlifetime"))) { - lifetime = tdata.get_value(string("gc_maxlifetime")).to_int(); - } - if (ctime < lifetime) { - // f$fclose(thandler); - return false; +static void session_close() { + if (get_sparam("handler").to_bool()) { + close_safe(get_sparam("handler").to_int()); } - // f$fclose(thandler); - return f$unlink(filepath); + reset_sparams(); } -static bool session_gc() { - Optional> sfiles = f$scandir(SM.get_sessions_path()); - if (sfiles.is_false()) { - php_warning("Failed to scan sessions directory %s\n", SM.get_sessions_path().c_str()); +static bool session_read() { + session_open(); + struct stat buf; + if (fstat(get_sparam("handler").to_int(), &buf) < 0) { + php_warning("Failed to read session data on path %s", get_sparam("file_path").to_string().c_str()); return false; } - fprintf(stdout, "result of scandir is:\n%s\n", f$serialize(sfiles.val()).c_str()); - auto nsfiles = sfiles.val().count(); - int n = 0; - for (auto sfile = sfiles.val().cbegin(); sfile != sfiles.val().cend(); ++sfile) { - string val = sfile.get_value().to_string(); - if (val == string(".") or val == string("..")) { - continue; - } - if (session_destroy(val)) { - ++n; - } - } - if (n != nsfiles) { - php_warning("Failed to delete all files in sessions dir %s\n", SM.get_sessions_path().c_str()); - return false; - } - return true; -} -bool SessionManager::session_close(bool immediate) { - if (handler.is_null()) { + if (buf.st_size == 0) { + v$_SESSION = array(); return true; } - - if (!f$fclose(handler)) { - // php_warning(); + + char result[buf.st_size]; + dl::enter_critical_section(); + int n = read(get_sparam("handler").to_int(), result, buf.st_size); + if (n < (int)buf.st_size) { + if (n == -1) { + php_warning("Read failed"); + } else { + php_warning("Read returned less bytes than requested"); + } + dl::leave_critical_section(); return false; } - session_reset_vars(); + dl::leave_critical_section(); - if (immediate or rand() % 100 > 75) { - session_gc(); + v$_SESSION = f$unserialize(string(result, n)); + fprintf(stdout, "session_open(): successfully read file: handler %lld, path %s\n", get_sparam("handler").to_int(), get_sparam("file_path").to_string().c_str()); + fprintf(stdout, "_SESSION is: \n"); + for (auto it = v$_SESSION.as_array().begin(); it != v$_SESSION.as_array().end(); ++it) { + fprintf(stdout, "%s : %s\n", it.get_key().to_string().c_str(), it.get_value().to_string().c_str()); } return true; } -static bool session_abort() { - if (SM.get_session_status()) { - SM.session_close(); - SM.set_session_status(0); - return true; - } - return false; -} - -static bool session_flush(bool write = false) { - if (!SM.get_session_status()) { - return false; - } - bool result = true; - if (write && !SM.session_write()) { - php_warning("Failed to write session data %s\n", SM.get_session_path().val().c_str()); - result = false; - } - - SM.set_session_status(0); - SM.session_close(); - return result; -} +// static bool session_write() { +// session_open(); +// // pass +// return true; +// } -static bool send_cookies() { - // 1. check whether headers were sent or not - // pass: need headers_sent() - - // 2. check session_name for deprecated symbols, if it's user supplied - if (strpbrk(SM.get_session_name().val().c_str(), "=,;.[ \t\r\n\013\014") != NULL) { +static bool session_send_cookie() { + if (strpbrk(get_sparam("name").to_string().c_str(), "=,;.[ \t\r\n\013\014") != NULL) { php_warning("session.name cannot contain any of the following '=,;.[ \\t\\r\\n\\013\\014'"); return false; } - // 3. encode session_name, if it's user supplied - int expire = SM.get_session_lifetime(); + int expire = get_sparam("cookie_lifetime").to_int(); if (expire > 0) { expire += std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } - string domain = !SM.get_cookie_domain().is_false() ? SM.get_cookie_domain().val() : string(""); - f$setcookie(SM.get_session_name().val(), f$urlencode(SM.get_session_id().val()), expire, string("/"), domain, SM.get_cookie_secure(), SM.get_cookie_httponly()); - fprintf(stdout, "successfully sent cookies for id %s\n", SM.get_session_id().val().c_str()); + string domain = get_sparam("cookie_domain").to_string(); + bool secure = get_sparam("cookie_secure").to_bool(); + bool httponly = get_sparam("cookie_httponly").to_bool(); + string sid = f$urlencode(get_sparam("session_id").to_string()); + string path = get_sparam("cookie_path").to_string(); + string name = get_sparam("name").to_string(); + + f$setcookie(name, sid, expire, path, domain, secure, httponly); return true; } static bool session_reset_id() { - if (SM.get_session_id().is_false()) { + if (!get_sparam("session_id").to_bool()) { php_warning("Cannot set session ID - session ID is not initialized"); return false; } - if (SM.get_send_cookie()) { - send_cookies(); - SM.set_send_cookie(0); + if (get_sparam("send_cookie").to_bool()) { + session_send_cookie(); + set_sparam("send_cookie", true); } - return true; } static bool session_initialize() { - SM.set_session_status(1); - - if (SM.get_session_id().is_false()) { - generate_session_id(); - if (SM.get_session_id().is_false()) { + set_sparam("session_status", true); + + if (!get_sparam("session_id").to_bool()) { + if (!session_generate_id()) { + php_warning( + "Failed to create session ID: %s (path: %s)", + get_sparam("name").to_string().c_str(), + get_sparam("save_path").to_string().c_str() + ); session_abort(); - php_warning("Failed to create session ID: %s (path: %s)", SM.get_session_name().val().c_str(), SM.get_session_path().val().c_str()); return false; } - SM.set_send_cookie(1); + set_sparam("send_cookie", true); } + fprintf(stdout, "session_initialize(): successfully generated id: %s\n", get_sparam("session_id").to_string().c_str()); - SM.session_open(); - if (SM.get_handler().is_null()) { + if (!session_open() or !session_reset_id() or !session_read()) { session_abort(); - // php_warning(); return false; } - - session_reset_id(); - if (!SM.session_read()) { - session_abort(); - php_warning("Failed to read session data: %s (path: %s)\n", SM.get_session_name().val().c_str(), SM.get_session_path().val().c_str()); - return false; - } + // session_gc() + // pass return true; } static bool session_start() { - // 1. check status of the session - if (SM.get_session_status()) { - if (SM.get_session_path().is_false()) { - php_warning("Ignoring session_start() because a session is already active (started from %s)", SM.get_session_path().val().c_str()); - } else { - php_warning("Ignoring session_start() because a session is already active"); - } + if (get_sparam("session_status").to_bool()) { + php_warning("Ignoring session_start() because a session is already active"); return false; } - SM.set_send_cookie(1); + set_sparam("send_cookie", true); - if (SM.get_session_name().is_false()) { - SM.set_session_name(string("PHPSESSID")); - } - fprintf(stdout, "session name is: %s\n", SM.get_session_name().val().c_str()); - - // 2. check id of session - if (SM.get_session_id().is_false()) { - // 4.1 try to get an id of session via it's name from _COOKIE - Optional pid{false}; - if (v$_COOKIE.as_array().has_key(SM.get_session_name().val())) { - pid = v$_COOKIE.get_value(SM.get_session_name().val()).to_string(); - fprintf(stdout, "found session id in cookies: %s\n", pid.val().c_str()); + if (!get_sparam("session_id").to_bool()) { + mixed id = false; + if (v$_COOKIE.as_array().isset(get_sparam("name").to_string())) { + id = v$_COOKIE.as_array().get_value(get_sparam("name").to_string()).to_string(); + fprintf(stdout, "Found id: %s\n", id.as_string().c_str()); } - if (!pid.is_false()) { - SM.set_send_cookie(0); - } - SM.set_session_id(pid); - } - // 5. check the id for dangerous symbols - if (!SM.get_session_id().is_false() && strpbrk(SM.get_session_id().val().c_str(), "\r\n\t <>'\"\\")) { - SM.set_session_id(false); + if (id.to_bool() && !id.to_string().empty()) { + if (!strpbrk(id.to_string().c_str(), "\r\n\t <>'\"\\")) { + fprintf(stdout, "id is valid\n"); + set_sparam("send_cookie", false); + set_sparam("session_id", id.to_string()); + } + } } - // 6. try to initialize the session if (!session_initialize()) { - SM.set_session_status(0); - SM.set_session_id(false); + set_sparam("session_status", false); + set_sparam("session_id", false); return false; } + return true; } +// static bool session_flush() { +// if (!get_sparam("session_status").to_bool()) { +// return false; +// } + +// session_write(); +// set_sparam("session_status", false); +// return true; +// } + } // namespace sessions bool f$session_start(const array &options) { - // 1. check status of session - if (sessions::SM.get_session_status()) { - if (sessions::SM.get_session_path().is_false()) { - php_warning("Ignoring session_start() because a session is already active (started from %s)", sessions::SM.get_session_path().val().c_str()); - } else { - php_warning("Ignoring session_start() because a session is already active"); - } - return true; + if (sessions::get_sparam("session_status").to_bool()) { + php_warning("Ignoring session_start() because a session is already active"); + return false; } - // 2. check whether headers were sent or not - // need headers_sent() - // pass - - bool read_and_close = false; - - // 3. parse the options arg and set it - if (!options.empty()) { - for (auto it = options.begin(); it != options.end(); ++it) { - string tkey = it.get_key().to_string(); - if (tkey == string("read_and_close")) { - read_and_close = it.get_value().to_bool(); - } else if (tkey == string("name")) { - sessions::SM.set_session_name(it.get_value().to_string()); - } else if (tkey == string("gc_maxlifetime")) { - sessions::SM.set_session_lifetime(it.get_value().to_int()); - } else if (tkey == string("cookie_path")) { - sessions::SM.set_session_path(it.get_value().to_string()); - } else if (tkey == string("cookie_lifetime")) { - sessions::SM.set_cookie_lifetime(it.get_value().to_int()); - } else if (tkey == string("cookie_domain")) { - sessions::SM.set_cookie_domain(it.get_value().to_string()); - } else if (tkey == string("cookie_secure")) { - sessions::SM.set_cookie_secure(it.get_value().to_bool()); - } else if (tkey == string("cookie_httponly")) { - sessions::SM.set_cookie_httponly(it.get_value().to_bool()); - } - } - } - fprintf(stdout, "Before session_start()\n"); + sessions::initialize_sparams(options); + sessions::print_sparams(); // to delete sessions::session_start(); - fprintf(stdout, "After session_start()\n"); - - // 4. check the status of the session - if (!sessions::SM.get_session_status()) { - // 4.1 clear cache of session variables - v$_SESSION = NULL; - // php_warning(); - return false; - } - // 5. check for read_and_close - if (read_and_close) { - sessions::session_flush(); + if (sessions::get_sparam("read_and_close").to_bool()) { + sessions::session_close(); } - return true; } -bool f$session_destroy() { - if (!sessions::SM.get_session_status()) { - php_warning("Trying to destroy uninitialized session"); - return false; - } - - if (sessions::SM.get_session_path().has_value()) { - return sessions::session_destroy(sessions::SM.get_session_path().val()); - } - sessions::SM.session_close(); - return false; -} - bool f$session_abort() { - if (!sessions::SM.get_session_status()) { - return false; - } - return sessions::session_abort(); -} - -int64_t f$session_status() { - return static_cast(sessions::SM.get_session_status()) + 1; -} - -bool f$session_write_close() { - if (!sessions::SM.get_session_status()) { + if (!sessions::get_sparam("session_status").to_bool()) { return false; } - return sessions::session_flush(1); -} - -bool $session_commit() { - return f$session_write_close(); + sessions::session_abort(); + return true; } - diff --git a/runtime/sessions.h b/runtime/sessions.h index e66a5d0c5e..61072c0992 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -1,79 +1,7 @@ #pragma once #include "runtime/kphp_core.h" -#include "common/mixin/not_copyable.h" -#include "common/smart_ptrs/singleton.h" - -namespace sessions { - -using Stream = mixed; - -class SessionManager : vk::not_copyable { -public: - bool session_open(); - bool session_close(bool immediate = false); - bool session_read(); - bool session_write(); - bool session_delete(); - - void session_reset_vars(); - - void set_session_status(const bool &status) noexcept { session_status = status; } - void set_session_path(const string &path) noexcept { session_path = path; } - void set_session_id(const Optional &sid) noexcept { id = sid; } - void set_send_cookie(const bool &val) noexcept { send_cookie = val; } - void set_session_name(const string &val) noexcept { session_name = val; } - void set_session_lifetime(const int &val) noexcept { session_lifetime = val; } - void set_handler(const Stream &stream) noexcept { handler = stream; } - - void set_cookie_domain(const string &val) noexcept { cookie_domain = val; } - void set_cookie_lifetime(const int &val) noexcept { cookie_lifetime = val; } - void set_cookie_secure(const bool &val) noexcept { cookie_secure = val; } - void set_cookie_httponly(const bool &val) noexcept { cookie_httponly = val; } - - bool get_session_status() noexcept { return session_status; } - Optional get_session_path() noexcept { return session_path; } - Optional get_session_id() noexcept { return id; } - bool get_send_cookie() noexcept { return send_cookie; } - Optional get_session_name() noexcept { return session_name; } - int get_session_lifetime() noexcept { return session_lifetime; } - Stream get_handler() noexcept {return handler; } - - string get_sessions_path() noexcept { return sessions_path; } - Optional get_cookie_domain() noexcept { return cookie_domain; } - int get_cookie_lifetime() noexcept { return cookie_lifetime; } - bool get_cookie_secure() noexcept { return cookie_secure; } - bool get_cookie_httponly() noexcept { return cookie_httponly; } - -private: - SessionManager(); - - Optional id{false}; - bool session_status{0}; - bool send_cookie{0}; - Optional session_path{false}; - Optional session_name{false}; // by default PHPSESSID (key for searching in the cookies) - int session_lifetime{1440}; - - int cookie_lifetime{0}; - Optional cookie_domain{false}; - bool cookie_secure{0}; - bool cookie_httponly{0}; - - string tempdir_path; // path to the /tmp - string sessions_path; // path to the dir with existing sessions - - Stream handler{NULL}; - - friend class vk::singleton; -}; - -} // namespace sessions +#include "runtime/interface.h" bool f$session_start(const array &options = array()); -bool f$session_abort(); -bool f$session_destroy(); -bool f$session_commit(); -bool f$session_write_close(); -int64_t f$session_status(); -Optional f$session_create_id(const string &prefix); +bool f$session_abort(); \ No newline at end of file From e6a68948750bd98edc4b5b7ab88a1e5904a4c3b2 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Tue, 2 Apr 2024 22:19:14 +0300 Subject: [PATCH 08/56] Refactor the code: add aliases for array keys. Implement other basic functions and simple logic for working with extra attributes for session files. --- builtin-functions/_functions.txt | 6 +- runtime/sessions.cpp | 390 +++++++++++++++++++++++-------- runtime/sessions.h | 13 +- 3 files changed, 305 insertions(+), 104 deletions(-) diff --git a/builtin-functions/_functions.txt b/builtin-functions/_functions.txt index f1cc67c6cc..0f83c41024 100644 --- a/builtin-functions/_functions.txt +++ b/builtin-functions/_functions.txt @@ -777,8 +777,12 @@ function session_abort() ::: bool; function session_commit() ::: bool; function session_write_close() ::: bool; function session_gc() ::: bool; -function session_status() ::: bool; +function session_status() ::: int; +function session_id($id ::: ?string = null) ::: string | false; function session_destroy() ::: bool; +function session_encode() ::: string | false; +function session_decode($data ::: string) ::: bool; +function session_get_cookie_params() ::: array; define('PHP_ROUND_HALF_UP', 123423141); define('PHP_ROUND_HALF_DOWN', 123423144); diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index c45e4dabfa..ec0b8d91fe 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "runtime/sessions.h" #include "runtime/files.h" @@ -8,6 +9,7 @@ #include "common/wrappers/to_array.h" #include "runtime/interface.h" #include "runtime/url.h" +#include "runtime/math_functions.h" namespace sessions { @@ -25,29 +27,52 @@ static bool session_valid_id(const string &id); static bool session_abort(); static bool session_reset_id(); static bool session_send_cookie(); -// static bool session_flush(); +static int session_gc(const bool &immediate); +static bool session_flush(); +static string session_encode(); +static bool session_decode(const string &data); static bool session_open(); static bool session_read(); -// static bool session_write(); +static bool session_write(); static void session_close(); -static void initialize_sparams(const array &options) noexcept { - // TO-DO: reconsider it - const auto skeys = vk::to_array>({ - {"read_and_close", false}, - {"save_path", string(getenv("TMPDIR")).append("sessions/")}, - {"name", string("PHPSESSID")}, - {"gc_maxlifetime", 1440}, - {"cookie_path", string("/")}, - {"cookie_lifetime", 0}, - {"cookie_domain", string("")}, - {"cookie_secure", false}, - {"cookie_httponly", false} - }); +constexpr static auto S_READ_CLOSE = "read_and_close"; +constexpr static auto S_ID = "session_id"; +constexpr static auto S_FD = "handler"; +constexpr static auto S_STATUS = "session_status"; +constexpr static auto S_OPENED = "is_opened"; +constexpr static auto S_DIR = "save_path"; +constexpr static auto S_PATH = "session_path"; +constexpr static auto S_NAME = "name"; +constexpr static auto S_CTIME = "session_ctime"; +constexpr static auto S_LIFETIME = "gc_maxlifetime"; +constexpr static auto S_PROBABILITY = "gc_probability"; +constexpr static auto S_DIVISOR = "gc_divisor"; +constexpr static auto S_SEND_COOKIE = "send_cookie"; +constexpr static auto C_PATH = "cookie_path"; +constexpr static auto C_LIFETIME = "cookie_lifetime"; +constexpr static auto C_DOMAIN = "cookie_domain"; +constexpr static auto C_SECURE = "cookie_secure"; +constexpr static auto C_HTTPONLY = "cookie_httponly"; + +// TO-DO: reconsider it +const auto skeys = vk::to_array>({ + {S_READ_CLOSE, false}, + {S_DIR, string(getenv("TMPDIR")).append("sessions/")}, + {S_NAME, string("PHPSESSID")}, + {S_LIFETIME, 1440}, + {S_PROBABILITY, 1}, + {S_DIVISOR, 100}, + {C_PATH, string("/")}, + {C_LIFETIME, 0}, + {C_DOMAIN, string("")}, + {C_SECURE, false}, + {C_HTTPONLY, false} +}); +static void initialize_sparams(const array &options) noexcept { reset_sparams(); - for (const auto& it : skeys) { if (options.isset(string(it.first))) { set_sparam(it.first, options.get_value(string(it.first))); @@ -57,17 +82,27 @@ static void initialize_sparams(const array &options) noexcept { } } -static void print_sparams() noexcept { - fprintf(stdout, "\nKPHPSESSARR is:\n"); - for (auto it = v$_KPHPSESSARR.as_array().begin(); it != v$_KPHPSESSARR.as_array().end(); ++it) { - fprintf(stdout, "%s : %s\n", it.get_key().to_string().c_str(), it.get_value().to_string().c_str()); +static array session_get_cookie_params() { + array result; + if (v$_KPHPSESSARR.as_array().empty()) { + php_warning("Session cookie params cannot be received when there is no active session. Returned the default params"); + result.emplace_value(string(C_PATH), skeys[6].second); + result.emplace_value(string(C_LIFETIME), skeys[7].second); + result.emplace_value(string(C_DOMAIN), skeys[8].second); + result.emplace_value(string(C_SECURE), skeys[9].second); + result.emplace_value(string(C_HTTPONLY), skeys[10].second); + } else { + result.emplace_value(string(C_PATH), get_sparam(C_PATH)); + result.emplace_value(string(C_LIFETIME), get_sparam(C_LIFETIME)); + result.emplace_value(string(C_DOMAIN), get_sparam(C_DOMAIN)); + result.emplace_value(string(C_SECURE), get_sparam(C_SECURE)); + result.emplace_value(string(C_HTTPONLY), get_sparam(C_HTTPONLY)); } - - fprintf(stdout, "\n%s\n", f$serialize(v$_KPHPSESSARR.as_array()).c_str()); + return result; } static void reset_sparams() noexcept { - v$_KPHPSESSARR = array(); + v$_KPHPSESSARR.as_array().clear(); } static mixed get_sparam(const char *key) noexcept { @@ -114,21 +149,33 @@ static bool session_generate_id() { php_warning("Failed to create new ID\n"); return false; } - set_sparam("session_id", id); + set_sparam(S_ID, id); return true; } static bool session_abort() { - if (get_sparam("session_status").to_bool()) { + if (get_sparam(S_STATUS).to_bool()) { session_close(); - set_sparam("session_status", false); return true; } return false; } +static string session_encode() { + return f$serialize(v$_SESSION.as_array()); +} + +static bool session_decode(const string &data) { + mixed buf = f$unserialize(data); + if (buf.is_bool()) { + return false; + } + v$_SESSION = buf.as_array(); + return true; +} + static bool session_open() { - if (get_sparam("handler").to_bool()) { + if (get_sparam(S_FD).to_bool()) { /* if we close the file for reopening it, the other worker may open it faster and the current process will stop @@ -136,206 +183,345 @@ static bool session_open() { return true; } - if (!f$file_exists(get_sparam("save_path").to_string())) { - f$mkdir(get_sparam("save_path").to_string()); - fprintf(stdout, "session_open(): successfully created dir: %s\n", get_sparam("save_path").to_string().c_str()); + if (!f$file_exists(get_sparam(S_DIR).to_string())) { + f$mkdir(get_sparam(S_DIR).to_string()); } - set_sparam("file_path", string(get_sparam("save_path").to_string()).append(get_sparam("session_id").to_string())); - set_sparam("handler", open_safe(get_sparam("file_path").to_string().c_str(), O_RDWR | O_CREAT, 0777)); + set_sparam(S_PATH, string(get_sparam(S_DIR).to_string()).append(get_sparam(S_ID).to_string())); + bool is_new = (!f$file_exists(get_sparam(S_PATH).to_string())) ? 1 : 0; + set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR | O_CREAT, 0777)); - if (get_sparam("handler").to_int() < 0) { - php_warning("Failed to open the file %s", get_sparam("file_path").to_string().c_str()); + if (get_sparam(S_FD).to_int() < 0) { + php_warning("Failed to open the file %s", get_sparam(S_PATH).to_string().c_str()); return false; } - fprintf(stdout, "session_open(): successfully opened file: handler %lld, path %s\n", get_sparam("handler").to_int(), get_sparam("file_path").to_string().c_str()); - if (flock(get_sparam("handler").to_int(), LOCK_EX) < 0) { - php_warning("Failed to lock the file %s", get_sparam("file_path").to_string().c_str()); + if (flock(get_sparam(S_FD).to_int(), LOCK_EX) < 0) { + php_warning("Failed to lock the file %s", get_sparam(S_PATH).to_string().c_str()); return false; } - - fprintf(stdout, "session_open(): successfully locked file: handler %lld, path %s\n", get_sparam("handler").to_int(), get_sparam("file_path").to_string().c_str()); + + // set new metadata to the file + int ret_ctime = getxattr(get_sparam(S_PATH).to_string().c_str(), S_CTIME, NULL, 0, 0, 0); + int ret_gc_lifetime = getxattr(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, NULL, 0, 0, 0); + if (is_new or ret_ctime < 0) { + // add the creation data to metadata of file + int ctime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + setxattr(get_sparam(S_PATH).to_string().c_str(), S_CTIME, &ctime, sizeof(int), 0, 0); + } + if (ret_gc_lifetime < 0) { + int gc_maxlifetime = get_sparam(S_LIFETIME).to_int(); + setxattr(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, &gc_maxlifetime, sizeof(int), 0, 0); + } + + int is_opened = 1; + setxattr(get_sparam(S_PATH).to_string().c_str(), S_OPENED, &is_opened, sizeof(int), 0, 0); return true; } static void session_close() { - if (get_sparam("handler").to_bool()) { - close_safe(get_sparam("handler").to_int()); + if (get_sparam(S_FD).to_bool()) { + close_safe(get_sparam(S_FD).to_int()); } + int is_opened = 0; + setxattr(get_sparam(S_PATH).to_string().c_str(), S_OPENED, &is_opened, sizeof(int), 0, 0); reset_sparams(); } static bool session_read() { session_open(); struct stat buf; - if (fstat(get_sparam("handler").to_int(), &buf) < 0) { - php_warning("Failed to read session data on path %s", get_sparam("file_path").to_string().c_str()); + if (fstat(get_sparam(S_FD).to_int(), &buf) < 0) { + php_warning("Failed to read session data on path %s", get_sparam(S_PATH).to_string().c_str()); return false; } if (buf.st_size == 0) { - v$_SESSION = array(); + v$_SESSION.as_array().clear(); return true; } char result[buf.st_size]; - dl::enter_critical_section(); - int n = read(get_sparam("handler").to_int(), result, buf.st_size); - if (n < (int)buf.st_size) { + ssize_t n = read_safe(get_sparam(S_FD).to_int(), result, buf.st_size, get_sparam(S_PATH).to_string()); + if (n < buf.st_size) { if (n == -1) { php_warning("Read failed"); } else { php_warning("Read returned less bytes than requested"); } - dl::leave_critical_section(); return false; } - dl::leave_critical_section(); - - v$_SESSION = f$unserialize(string(result, n)); - fprintf(stdout, "session_open(): successfully read file: handler %lld, path %s\n", get_sparam("handler").to_int(), get_sparam("file_path").to_string().c_str()); - fprintf(stdout, "_SESSION is: \n"); - for (auto it = v$_SESSION.as_array().begin(); it != v$_SESSION.as_array().end(); ++it) { - fprintf(stdout, "%s : %s\n", it.get_key().to_string().c_str(), it.get_value().to_string().c_str()); + + if (!session_decode(string(result, n))) { + php_warning("Failed to unzerialize the data"); + return false; } return true; } -// static bool session_write() { -// session_open(); -// // pass -// return true; -// } +static bool session_write() { + session_open(); + string data = f$serialize(v$_SESSION.as_array()); + ssize_t n = write_safe(get_sparam("handler").to_int(), data.c_str(), data.size(), get_sparam("file_path").to_string()); + if (n < data.size()) { + if (n == -1) { + php_warning("Write failed"); + } else { + php_warning("Write wrote less bytes than requested"); + } + return false; + } + return true; +} static bool session_send_cookie() { - if (strpbrk(get_sparam("name").to_string().c_str(), "=,;.[ \t\r\n\013\014") != NULL) { + if (strpbrk(get_sparam(S_NAME).to_string().c_str(), "=,;.[ \t\r\n\013\014") != NULL) { php_warning("session.name cannot contain any of the following '=,;.[ \\t\\r\\n\\013\\014'"); return false; } - int expire = get_sparam("cookie_lifetime").to_int(); + int expire = get_sparam(C_LIFETIME).to_int(); if (expire > 0) { expire += std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } - string domain = get_sparam("cookie_domain").to_string(); - bool secure = get_sparam("cookie_secure").to_bool(); - bool httponly = get_sparam("cookie_httponly").to_bool(); - string sid = f$urlencode(get_sparam("session_id").to_string()); - string path = get_sparam("cookie_path").to_string(); - string name = get_sparam("name").to_string(); + string domain = get_sparam(C_DOMAIN).to_string(); + bool secure = get_sparam(C_SECURE).to_bool(); + bool httponly = get_sparam(C_HTTPONLY).to_bool(); + string sid = f$urlencode(get_sparam(S_ID).to_string()); + string path = get_sparam(C_PATH).to_string(); + string name = get_sparam(S_NAME).to_string(); f$setcookie(name, sid, expire, path, domain, secure, httponly); return true; } static bool session_reset_id() { - if (!get_sparam("session_id").to_bool()) { + if (!get_sparam(S_ID).to_bool()) { php_warning("Cannot set session ID - session ID is not initialized"); return false; } - if (get_sparam("send_cookie").to_bool()) { + if (get_sparam(S_SEND_COOKIE).to_bool()) { session_send_cookie(); - set_sparam("send_cookie", true); + set_sparam(S_SEND_COOKIE, false); } return true; } +static bool session_expired(const string &path) { + int ctime, lifetime; + int ret_ctime = getxattr(path.c_str(), S_CTIME, &ctime, sizeof(int), 0, 0); + int ret_lifetime = getxattr(path.c_str(), S_LIFETIME, &lifetime, sizeof(int), 0, 0); + if (ret_ctime < 0 or ret_lifetime < 0) { + php_warning("Failed to get metadata of the file on path: %s", path.c_str()); + return false; + } + + int now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + if (ctime + lifetime <= now) { + return true; + } + return false; +} + +static int session_gc(const bool &immediate = false) { + double prob = f$lcg_value() * get_sparam(S_DIVISOR).to_float(); + double s_prob = get_sparam(S_PROBABILITY).to_float(); + if ((!immediate) && ((s_prob <= 0) or (prob >= s_prob))) { + return -1; + } + + mixed s_list = f$scandir(get_sparam(S_DIR).to_string()); + if (!s_list.to_bool()) { + php_warning("Failed to scan the session directory on the save_path: %s", get_sparam(S_DIR).to_string().c_str()); + return -1; + } + + int result = 0; + for (auto s = s_list.as_array().begin(); s != s_list.as_array().end(); ++s) { + string path = s.get_value().to_string(); + if (path == string(".") or path == string("..")) { + continue; + } + path = string(get_sparam(S_DIR).to_string()).append(path); + if (path == get_sparam(S_PATH).to_string()) { + continue; + } + int is_opened; + int ret_code = getxattr(path.c_str(), S_OPENED, &is_opened, sizeof(int), 0, 0); + if (ret_code < 0) { + php_warning("Failed to get metadata of the file on path: %s", path.c_str()); + continue; + } else if (is_opened) { + // TO-DO: fix the bug with always opened tags in the session files + // continue; + } + + if (session_expired(path)) { + f$unlink(path); + ++result; + } + } + return result; +} + static bool session_initialize() { - set_sparam("session_status", true); + set_sparam(S_STATUS, true); - if (!get_sparam("session_id").to_bool()) { + if (!get_sparam(S_ID).to_bool()) { if (!session_generate_id()) { php_warning( "Failed to create session ID: %s (path: %s)", - get_sparam("name").to_string().c_str(), - get_sparam("save_path").to_string().c_str() + get_sparam(S_NAME).to_string().c_str(), + get_sparam(S_PATH).to_string().c_str() ); session_abort(); return false; } - set_sparam("send_cookie", true); + set_sparam(S_SEND_COOKIE, true); } - fprintf(stdout, "session_initialize(): successfully generated id: %s\n", get_sparam("session_id").to_string().c_str()); if (!session_open() or !session_reset_id() or !session_read()) { session_abort(); return false; } - // session_gc() - // pass + session_gc(0); return true; } static bool session_start() { - if (get_sparam("session_status").to_bool()) { + if (get_sparam(S_STATUS).to_bool()) { php_warning("Ignoring session_start() because a session is already active"); return false; } - set_sparam("send_cookie", true); + set_sparam(S_SEND_COOKIE, true); - if (!get_sparam("session_id").to_bool()) { + if (!get_sparam(S_ID).to_bool()) { mixed id = false; - if (v$_COOKIE.as_array().isset(get_sparam("name").to_string())) { - id = v$_COOKIE.as_array().get_value(get_sparam("name").to_string()).to_string(); - fprintf(stdout, "Found id: %s\n", id.as_string().c_str()); + if (v$_COOKIE.as_array().isset(get_sparam(S_NAME).to_string())) { + id = v$_COOKIE.as_array().get_value(get_sparam(S_NAME).to_string()).to_string(); } if (id.to_bool() && !id.to_string().empty()) { if (!strpbrk(id.to_string().c_str(), "\r\n\t <>'\"\\")) { - fprintf(stdout, "id is valid\n"); - set_sparam("send_cookie", false); - set_sparam("session_id", id.to_string()); + if (f$file_exists(string(get_sparam(S_DIR).to_string()).append(id.to_string()))) { + set_sparam(S_SEND_COOKIE, false); + set_sparam(S_ID, id.to_string()); + } } } } if (!session_initialize()) { - set_sparam("session_status", false); - set_sparam("session_id", false); + set_sparam(S_STATUS, false); + set_sparam(S_ID, false); return false; } return true; } -// static bool session_flush() { -// if (!get_sparam("session_status").to_bool()) { -// return false; -// } +static bool session_flush() { + if (!get_sparam(S_STATUS).to_bool()) { + return false; + } -// session_write(); -// set_sparam("session_status", false); -// return true; -// } + session_write(); + session_close(); + return true; +} } // namespace sessions bool f$session_start(const array &options) { - if (sessions::get_sparam("session_status").to_bool()) { + if (sessions::get_sparam(sessions::S_STATUS).to_bool()) { php_warning("Ignoring session_start() because a session is already active"); return false; } sessions::initialize_sparams(options); - sessions::print_sparams(); // to delete sessions::session_start(); - if (sessions::get_sparam("read_and_close").to_bool()) { + if (sessions::get_sparam(sessions::S_READ_CLOSE).to_bool()) { sessions::session_close(); } return true; } bool f$session_abort() { - if (!sessions::get_sparam("session_status").to_bool()) { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { return false; } sessions::session_abort(); return true; } + +Optional f$session_gc() { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Session cannot be garbage collected when there is no active session"); + return false; + } + int result = sessions::session_gc(1); + return (result <= 0) ? Optional{false} : Optional{result}; +} + +bool f$session_write_close() { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + return false; + } + sessions::session_flush(); + return true; +} + +bool f$session_commit() { + return f$session_write_close(); +} + +int64_t f$session_status() { + return sessions::get_sparam(sessions::S_STATUS).to_int() + 1; +} + +Optional f$session_encode() { + return Optional{sessions::session_encode()}; +} + +bool f$session_decode(const string &data) { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Session data cannot be decoded when there is no active session"); + return false; + } + return sessions::session_decode(data); +} + +array f$session_get_cookie_params() { + return sessions::session_get_cookie_params(); +} + +// TO-DO: is this correct? +bool f$session_destroy() { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Trying to destroy uninitialized session"); + return false; + } + sessions::session_close(); + return true; +} + +// TO-DO: implement function for changing id of existing session +/* +Optional f$session_id(Optional id) { + if (id.has_value() && sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Session ID cannot be changed when a session is active"); + return Optional{false}; + } + // TO-DO: check headers_sent() + if (id.has_value()) { + sessions::set_sparam(sessions::S_ID, string(id)); + } + return Optional{sessions::get_sparam(sessions::S_ID).to_string()}; +} +*/ \ No newline at end of file diff --git a/runtime/sessions.h b/runtime/sessions.h index 61072c0992..2de3ae7c14 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -4,4 +4,15 @@ #include "runtime/interface.h" bool f$session_start(const array &options = array()); -bool f$session_abort(); \ No newline at end of file +bool f$session_abort(); +bool f$session_commit(); +bool f$session_write_close(); +Optional f$session_gc(); +int64_t f$session_status(); +Optional f$session_encode(); +bool f$session_decode(const string &data); +array f$session_get_cookie_params(); + +// TO-DO: +// bool f$session_destroy(); +// Optional f$session_id(Optional id = Optional()); \ No newline at end of file From 5e0454886a8ace7313b2f81a9a3f07edea687245 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Mon, 8 Jul 2024 17:50:52 +0300 Subject: [PATCH 09/56] Add session_id function for output id --- runtime/sessions.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index ec0b8d91fe..e975756f57 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -57,7 +57,7 @@ constexpr static auto C_SECURE = "cookie_secure"; constexpr static auto C_HTTPONLY = "cookie_httponly"; // TO-DO: reconsider it -const auto skeys = vk::to_array>({ +const auto skeys = vk::to_array>({ {S_READ_CLOSE, false}, {S_DIR, string(getenv("TMPDIR")).append("sessions/")}, {S_NAME, string("PHPSESSID")}, @@ -355,7 +355,7 @@ static int session_gc(const bool &immediate = false) { continue; } else if (is_opened) { // TO-DO: fix the bug with always opened tags in the session files - // continue; + continue; } if (session_expired(path)) { @@ -511,6 +511,14 @@ bool f$session_destroy() { return true; } +Optional f$session_id() { + // if (sessions::get_sparam(sessions::S_STATUS).to_bool()) { + // php_warning("Session ID cannot be changed when a session is active"); + // return Optional{false}; + // } + return Optional{sessions::get_sparam(sessions::S_ID).to_string()}; +} + // TO-DO: implement function for changing id of existing session /* Optional f$session_id(Optional id) { From 33764f15767bb050417ddf7b03242e15148751d3 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Mon, 8 Jul 2024 17:52:08 +0300 Subject: [PATCH 10/56] Add first php test --- tests/phpt/sessions/01.php | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/phpt/sessions/01.php diff --git a/tests/phpt/sessions/01.php b/tests/phpt/sessions/01.php new file mode 100644 index 0000000000..da1a1d95b3 --- /dev/null +++ b/tests/phpt/sessions/01.php @@ -0,0 +1,51 @@ +@ok +session_id = false; + } + + function handleRequest(): ?KphpJobWorkerResponse { + $response = new Response(); + $status = session_start(); + if ($status) { + + } + $response->session_id = + } +} + +class Response implements KphpJobWorkerResponse { + /** @var AI */ + public $ai = null; + + /** @var string|false */ + public $session_id = false; +} + + +$request1 = new Request(); +$request1->ai = new A1(); +$request2 = Request(); +$request2->ai = new A2(); +$ids = array(); +kphp_job_worker_start($request, -1); + + From 718951bc6862e27c06020fcbacd79af279c65b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 10 Jul 2024 01:18:01 +0300 Subject: [PATCH 11/56] init --- .github/workflows/Build.yml | 34 +++++++++++++++++++++++++++++++--- .github/workflows/debian.yml | 11 +++++++++-- .github/workflows/ubuntu.yml | 23 ++++++++++++++++++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index d3c8d31e5f..820f695dd6 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -23,23 +23,51 @@ jobs: cpp: 17 asan: off ubsan: off + light_runtime: off + - os: buster + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on - os: focal compiler: clang++ cpp: 17 asan: off ubsan: on + light_runtime: off + - os: focal + compiler: clang++ + cpp: 17 + asan: off + ubsan: on + light_runtime: on - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off + light_runtime: off + - os: focal + compiler: g++-10 + cpp: 20 + asan: on + ubsan: off + light_runtime: on - os: jammy compiler: g++ cpp: 20 asan: on ubsan: off - - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" + light_runtime: off + - os: jammy + compiler: g++ + cpp: 20 + asan: on + ubsan: off + light_runtime: on + + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" steps: - uses: actions/checkout@v3 @@ -78,7 +106,7 @@ jobs: - name: Build all run: docker exec kphp-build-container-${{matrix.os}} bash -c - "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" + "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DCOMPILE_RUNTIME_LIGHT=${{matrix.light_runtime}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" - name: Run unit tests run: docker exec kphp-build-container-${{matrix.os}} bash -c diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 2d507d8110..1d365bd178 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -21,8 +21,15 @@ jobs: cpp: 17 asan: off ubsan: off + light_runtime: off + - os: buster + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" steps: - uses: actions/checkout@v3 @@ -59,7 +66,7 @@ jobs: - name: Build all run: docker exec -u kitten kphp-build-container-${{matrix.os}} bash -c - "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" + "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DCOMPILE_RUNTIME_LIGHT=${{matrix.light_runtime}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" - name: Run unit tests run: docker exec -u kitten kphp-build-container-${{matrix.os}} bash -c diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 49af16bd9f..0280b01a48 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,18 +21,39 @@ jobs: cpp: 17 asan: off ubsan: off + light_runtime: off + - os: jammy + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on - os: focal compiler: clang++ cpp: 17 asan: off ubsan: on + light_runtime: off + - os: focal + compiler: clang++ + cpp: 17 + asan: off + ubsan: on + light_runtime: on + - os: focal + compiler: g++-10 + cpp: 20 + asan: on + ubsan: off + light_runtime: off - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off + light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" steps: - uses: actions/checkout@v3 From 5db00ea3fdaf2ec29108e3048eb97c9f0e08f150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 10 Jul 2024 01:25:29 +0300 Subject: [PATCH 12/56] temporaly disable buster build die to sury issue --- .github/workflows/Build.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 820f695dd6..65b52c17b1 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -18,18 +18,18 @@ jobs: strategy: matrix: include: - - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: off - - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on + # - os: buster + # compiler: g++ + # cpp: 17 + # asan: off + # ubsan: off + # light_runtime: off + # - os: buster + # compiler: g++ + # cpp: 17 + # asan: off + # ubsan: off + # light_runtime: on - os: focal compiler: clang++ cpp: 17 From a2d8afb232afab8afb626ea69b0a1690112248fe Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 10 Jul 2024 10:21:01 +0300 Subject: [PATCH 13/56] Add session_id(), hide session_destroy() --- runtime/sessions.cpp | 45 ++++++++++++++++++-------------------------- runtime/sessions.h | 6 +++--- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index e975756f57..ffa31dcc4c 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -72,7 +72,6 @@ const auto skeys = vk::to_array>({ }); static void initialize_sparams(const array &options) noexcept { - reset_sparams(); for (const auto& it : skeys) { if (options.isset(string(it.first))) { set_sparam(it.first, options.get_value(string(it.first))); @@ -316,7 +315,7 @@ static bool session_expired(const string &path) { if (ret_ctime < 0 or ret_lifetime < 0) { php_warning("Failed to get metadata of the file on path: %s", path.c_str()); return false; - } + } int now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); if (ctime + lifetime <= now) { @@ -414,6 +413,8 @@ static bool session_start() { } } } + } else if (strpbrk(get_sparam(S_ID).to_string().c_str(), "\r\n\t <>'\"\\")) { + set_sparam(S_ID, false); } if (!session_initialize()) { @@ -501,35 +502,25 @@ array f$session_get_cookie_params() { return sessions::session_get_cookie_params(); } -// TO-DO: is this correct? -bool f$session_destroy() { - if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { - php_warning("Trying to destroy uninitialized session"); - return false; - } - sessions::session_close(); - return true; -} - -Optional f$session_id() { - // if (sessions::get_sparam(sessions::S_STATUS).to_bool()) { - // php_warning("Session ID cannot be changed when a session is active"); - // return Optional{false}; - // } - return Optional{sessions::get_sparam(sessions::S_ID).to_string()}; -} - -// TO-DO: implement function for changing id of existing session -/* -Optional f$session_id(Optional id) { +Optional f$session_id(const Optional &id) { if (id.has_value() && sessions::get_sparam(sessions::S_STATUS).to_bool()) { php_warning("Session ID cannot be changed when a session is active"); return Optional{false}; } - // TO-DO: check headers_sent() + + mixed prev_id = sessions::get_sparam(sessions::S_ID); if (id.has_value()) { - sessions::set_sparam(sessions::S_ID, string(id)); + sessions::set_sparam(sessions::S_ID, id.val()); } - return Optional{sessions::get_sparam(sessions::S_ID).to_string()}; + return (prev_id.is_bool()) ? Optional{false} : Optional(prev_id.as_string()); } -*/ \ No newline at end of file + +// TO-DO +// bool f$session_destroy() { +// if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { +// php_warning("Trying to destroy uninitialized session"); +// return false; +// } +// sessions::session_close(); +// return true; +// } diff --git a/runtime/sessions.h b/runtime/sessions.h index 2de3ae7c14..caf9f6b70b 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -12,7 +12,7 @@ int64_t f$session_status(); Optional f$session_encode(); bool f$session_decode(const string &data); array f$session_get_cookie_params(); +Optional f$session_id(const Optional &id = Optional()); -// TO-DO: -// bool f$session_destroy(); -// Optional f$session_id(Optional id = Optional()); \ No newline at end of file +// TO-DO +// bool f$session_destroy(); \ No newline at end of file From c42a920454f8271a85886e5716d0cffea728f113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 10 Jul 2024 20:52:04 +0300 Subject: [PATCH 14/56] update --- .github/workflows/Build.yml | 44 +++++++++++------------------ .github/workflows/Dockerfile.buster | 8 +++--- .github/workflows/debian.yml | 6 ++++ .github/workflows/ubuntu.yml | 23 +-------------- 4 files changed, 27 insertions(+), 54 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 65b52c17b1..14c8941479 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -18,54 +18,42 @@ jobs: strategy: matrix: include: - # - os: buster - # compiler: g++ - # cpp: 17 - # asan: off - # ubsan: off - # light_runtime: off - # - os: buster - # compiler: g++ - # cpp: 17 - # asan: off - # ubsan: off - # light_runtime: on - - os: focal - compiler: clang++ + - os: buster + compiler: g++ cpp: 17 asan: off - ubsan: on + ubsan: off light_runtime: off - - os: focal + - os: buster + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on + - os: buster compiler: clang++ cpp: 17 asan: off - ubsan: on + ubsan: off light_runtime: on - os: focal - compiler: g++-10 - cpp: 20 - asan: on - ubsan: off + compiler: clang++ + cpp: 17 + asan: off + ubsan: on light_runtime: off - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off - light_runtime: on - - os: jammy - compiler: g++ - cpp: 20 - asan: on - ubsan: off light_runtime: off - os: jammy compiler: g++ cpp: 20 asan: on ubsan: off - light_runtime: on + light_runtime: off name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" diff --git a/.github/workflows/Dockerfile.buster b/.github/workflows/Dockerfile.buster index 908dbaed10..432855b3c9 100644 --- a/.github/workflows/Dockerfile.buster +++ b/.github/workflows/Dockerfile.buster @@ -8,8 +8,8 @@ RUN apt-get update && \ echo "deb https://archive.debian.org/debian buster-backports main" >> /etc/apt/sources.list && \ wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp buster main" >> /etc/apt/sources.list && \ - wget -qO - https://packages.sury.org/php/apt.gpg | apt-key add - && \ - echo "deb https://packages.sury.org/php/ buster main" >> /etc/apt/sources.list.d/php.list && \ + wget -qO - https://debian.octopuce.fr/snapshots/sury-php/buster-latest/apt.gpg | apt-key add - && \ + echo "deb https://debian.octopuce.fr/snapshots/sury-php/buster-latest/ buster main" >> /etc/apt/sources.list && \ TEMP_DEB="$(mktemp)" && \ wget -O "$TEMP_DEB" 'https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb' && \ dpkg -i "$TEMP_DEB" && \ @@ -19,8 +19,8 @@ RUN apt-get update && \ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake-data=3.18* cmake=3.18* make g++ gperf netcat \ - python3.7 python3-dev libpython3-dev python3-pip python3-setuptools mysql-server libmysqlclient-dev && \ + git cmake-data=3.18* cmake=3.18* make g++-10 clang++ gperf netcat \ + python3.7 python3-dev libpython3-dev python3-pip python3-setuptools python3-wheel mysql-server libmysqlclient-dev && \ pip3 install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 1d365bd178..d4c9130881 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -28,6 +28,12 @@ jobs: asan: off ubsan: off light_runtime: on + - os: buster + compiler: clang++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0280b01a48..49af16bd9f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,39 +21,18 @@ jobs: cpp: 17 asan: off ubsan: off - light_runtime: off - - os: jammy - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on - os: focal compiler: clang++ cpp: 17 asan: off ubsan: on - light_runtime: off - - os: focal - compiler: clang++ - cpp: 17 - asan: off - ubsan: on - light_runtime: on - - os: focal - compiler: g++-10 - cpp: 20 - asan: on - ubsan: off - light_runtime: off - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off - light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" steps: - uses: actions/checkout@v3 From 08c5a047c4377aa07914d6dec521c8965aafa5d0 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 10 Jul 2024 11:34:33 +0300 Subject: [PATCH 15/56] Fix tags, change flock, add macros - add aliases with macros: getxattr(), setxattr() -> get_tag(), set_tag(), - change flock() -> fcntl() with F_SETLKW, - add an additional check for the validity of file descriptor in session_close() --- runtime/sessions.cpp | 87 ++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index ffa31dcc4c..f587c1192f 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "runtime/sessions.h" #include "runtime/files.h" @@ -41,7 +42,6 @@ constexpr static auto S_READ_CLOSE = "read_and_close"; constexpr static auto S_ID = "session_id"; constexpr static auto S_FD = "handler"; constexpr static auto S_STATUS = "session_status"; -constexpr static auto S_OPENED = "is_opened"; constexpr static auto S_DIR = "save_path"; constexpr static auto S_PATH = "session_path"; constexpr static auto S_NAME = "name"; @@ -71,6 +71,22 @@ const auto skeys = vk::to_array>({ {C_HTTPONLY, false} }); +static int set_tag(const char *path, const char *name, void *value, const size_t size) { +#if defined(__APPLE__) + return setxattr(path, name, value, size, 0, 0); +#else + return setxattr(path, name, value, size, 0); +#endif +} + +static int get_tag(const char *path, const char *name, void *value, const size_t size) { +#if defined(__APPLE__) + return getxattr(path, name, value, size, 0, 0); +#else + return getxattr(path, name, value, size); +#endif +} + static void initialize_sparams(const array &options) noexcept { for (const auto& it : skeys) { if (options.isset(string(it.first))) { @@ -174,11 +190,7 @@ static bool session_decode(const string &data) { } static bool session_open() { - if (get_sparam(S_FD).to_bool()) { - /* - if we close the file for reopening it, - the other worker may open it faster and the current process will stop - */ + if (get_sparam(S_FD).to_bool() && (fcntl(get_sparam(S_FD).to_int(), F_GETFD) != -1 || errno != EBADF)) { return true; } @@ -188,6 +200,8 @@ static bool session_open() { set_sparam(S_PATH, string(get_sparam(S_DIR).to_string()).append(get_sparam(S_ID).to_string())); bool is_new = (!f$file_exists(get_sparam(S_PATH).to_string())) ? 1 : 0; + + // the interprocessor lock does not work set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR | O_CREAT, 0777)); if (get_sparam(S_FD).to_int() < 0) { @@ -195,36 +209,40 @@ static bool session_open() { return false; } - if (flock(get_sparam(S_FD).to_int(), LOCK_EX) < 0) { - php_warning("Failed to lock the file %s", get_sparam(S_PATH).to_string().c_str()); - return false; - } + struct flock lock; + lock.l_type = F_WRLCK; // Exclusive write lock + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + + int ret = fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + + if (ret < 0 && errno == EDEADLK) { + php_warning("Attempt to lock alredy locked session file, path: %s", get_sparam(S_PATH).to_string().c_str()); + return false; + } // set new metadata to the file - int ret_ctime = getxattr(get_sparam(S_PATH).to_string().c_str(), S_CTIME, NULL, 0, 0, 0); - int ret_gc_lifetime = getxattr(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, NULL, 0, 0, 0); + int ret_ctime = get_tag(get_sparam(S_PATH).to_string().c_str(), S_CTIME, NULL, 0); + int ret_gc_lifetime = get_tag(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, NULL, 0); if (is_new or ret_ctime < 0) { // add the creation data to metadata of file int ctime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - setxattr(get_sparam(S_PATH).to_string().c_str(), S_CTIME, &ctime, sizeof(int), 0, 0); + set_tag(get_sparam(S_PATH).to_string().c_str(), S_CTIME, &ctime, sizeof(int)); } if (ret_gc_lifetime < 0) { int gc_maxlifetime = get_sparam(S_LIFETIME).to_int(); - setxattr(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, &gc_maxlifetime, sizeof(int), 0, 0); + set_tag(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, &gc_maxlifetime, sizeof(int)); } - int is_opened = 1; - setxattr(get_sparam(S_PATH).to_string().c_str(), S_OPENED, &is_opened, sizeof(int), 0, 0); - return true; } static void session_close() { - if (get_sparam(S_FD).to_bool()) { + if (get_sparam(S_FD).to_bool() && (fcntl(get_sparam(S_FD).to_int(), F_GETFD) != -1 || errno != EBADF)) { close_safe(get_sparam(S_FD).to_int()); } - int is_opened = 0; - setxattr(get_sparam(S_PATH).to_string().c_str(), S_OPENED, &is_opened, sizeof(int), 0, 0); reset_sparams(); } @@ -262,7 +280,7 @@ static bool session_read() { static bool session_write() { session_open(); string data = f$serialize(v$_SESSION.as_array()); - ssize_t n = write_safe(get_sparam("handler").to_int(), data.c_str(), data.size(), get_sparam("file_path").to_string()); + ssize_t n = write_safe(get_sparam(S_FD).to_int(), data.c_str(), data.size(), get_sparam(S_PATH).to_string()); if (n < data.size()) { if (n == -1) { php_warning("Write failed"); @@ -310,8 +328,8 @@ static bool session_reset_id() { static bool session_expired(const string &path) { int ctime, lifetime; - int ret_ctime = getxattr(path.c_str(), S_CTIME, &ctime, sizeof(int), 0, 0); - int ret_lifetime = getxattr(path.c_str(), S_LIFETIME, &lifetime, sizeof(int), 0, 0); + int ret_ctime = get_tag(path.c_str(), S_CTIME, &ctime, sizeof(int)); + int ret_lifetime = get_tag(path.c_str(), S_LIFETIME, &lifetime, sizeof(int)); if (ret_ctime < 0 or ret_lifetime < 0) { php_warning("Failed to get metadata of the file on path: %s", path.c_str()); return false; @@ -337,6 +355,13 @@ static int session_gc(const bool &immediate = false) { return -1; } + struct flock lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + int result = 0; for (auto s = s_list.as_array().begin(); s != s_list.as_array().end(); ++s) { string path = s.get_value().to_string(); @@ -347,14 +372,15 @@ static int session_gc(const bool &immediate = false) { if (path == get_sparam(S_PATH).to_string()) { continue; } - int is_opened; - int ret_code = getxattr(path.c_str(), S_OPENED, &is_opened, sizeof(int), 0, 0); - if (ret_code < 0) { - php_warning("Failed to get metadata of the file on path: %s", path.c_str()); + + int fd; + if ((fd = open(path.c_str(), O_RDWR, 0777)) < 0) { + php_warning("Failed to open file on path: %s", path.c_str()); + continue; + } + + if (fcntl(fd, F_SETLK, &lock) < 0) { continue; - } else if (is_opened) { - // TO-DO: fix the bug with always opened tags in the session files - continue; } if (session_expired(path)) { @@ -507,7 +533,6 @@ Optional f$session_id(const Optional &id) { php_warning("Session ID cannot be changed when a session is active"); return Optional{false}; } - mixed prev_id = sessions::get_sparam(sessions::S_ID); if (id.has_value()) { sessions::set_sparam(sessions::S_ID, id.val()); From b2ecb61bcbf97a3c27c81d6d0436e4e626c32839 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 10 Jul 2024 23:24:06 +0300 Subject: [PATCH 16/56] Add cpp-tests (within single process (worker)) - session_id(), - session_start(), - session_status() --- tests/cpp/runtime/runtime-tests.cmake | 3 +- tests/cpp/runtime/sessions-test.cpp | 54 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/cpp/runtime/sessions-test.cpp diff --git a/tests/cpp/runtime/runtime-tests.cmake b/tests/cpp/runtime/runtime-tests.cmake index 731da98fe6..1466b1a33d 100644 --- a/tests/cpp/runtime/runtime-tests.cmake +++ b/tests/cpp/runtime/runtime-tests.cmake @@ -21,7 +21,8 @@ prepend(RUNTIME_TESTS_SOURCES ${BASE_DIR}/tests/cpp/runtime/ memory_resource/unsynchronized_pool_resource-test.cpp string-list-test.cpp string-test.cpp - zstd-test.cpp) + zstd-test.cpp + sessions-test.cpp) allow_deprecated_declarations_for_apple(${BASE_DIR}/tests/cpp/runtime/inter-process-mutex-test.cpp) vk_add_unittest(runtime "${RUNTIME_LIBS};${RUNTIME_LINK_TEST_LIBS}" ${RUNTIME_TESTS_SOURCES}) diff --git a/tests/cpp/runtime/sessions-test.cpp b/tests/cpp/runtime/sessions-test.cpp new file mode 100644 index 0000000000..2354389912 --- /dev/null +++ b/tests/cpp/runtime/sessions-test.cpp @@ -0,0 +1,54 @@ +#include + +#include "runtime/files.h" +#include "runtime/sessions.h" + +TEST(sessions_test, test_session_id_with_invalid_id) { + const string dir_path = string(getenv("TMPDIR")).append("sessions/"); + const string id = string("\t12345678\\\r"); + ASSERT_FALSE(f$session_id(id).has_value()); + ASSERT_TRUE(f$session_start()); + ASSERT_NE(f$session_id().val(), id); + + const string full_path = string(dir_path).append(f$session_id().val()); + ASSERT_TRUE(f$file_exists(full_path)); + ASSERT_TRUE(f$session_abort()); +} + +TEST(sessions_test, test_session_id_with_valid_id) { + const string dir_path = string(getenv("TMPDIR")).append("sessions/"); + const string id = string("sess_668d4f818ca3b"); + ASSERT_FALSE(f$session_id(id).has_value()); + ASSERT_TRUE(f$session_start()); + ASSERT_EQ(f$session_id().val(), id); + + const string full_path = string(dir_path).append(id); + ASSERT_TRUE(f$file_exists(full_path)); + ASSERT_TRUE(f$session_abort()); +} + +TEST(sessions_test, test_session_start) { + ASSERT_TRUE(f$session_start()); + ASSERT_FALSE(f$session_start()); + ASSERT_TRUE(f$session_abort()); +} + +TEST(sessions_test, test_session_start_with_params) { + array predefined_consts = array(); + const string dir_path = string(getenv("TMPDIR")).append("example/"); + predefined_consts.emplace_value(string("save_path"), dir_path); + ASSERT_TRUE(f$session_start(predefined_consts)); + ASSERT_TRUE(f$file_exists(string(dir_path).append(f$session_id().val()))); + ASSERT_TRUE(f$session_abort()); +} + +TEST(sessions_test, test_session_status) { + const int SESSION_NONE = 1; + const int SESSION_ACTIVE = 2; + + ASSERT_EQ(f$session_status(), SESSION_NONE); + ASSERT_TRUE(f$session_start()); + ASSERT_EQ(f$session_status(), SESSION_ACTIVE); + ASSERT_TRUE(f$session_abort()); + ASSERT_EQ(f$session_status(), SESSION_NONE); +} \ No newline at end of file From bab9c4efb7757358293d0651d1930d7784e0fe84 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Fri, 12 Jul 2024 15:32:37 +0300 Subject: [PATCH 17/56] Add unlock fcntl to the session_close() and rewind logic in session_write() --- runtime/sessions.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index f587c1192f..ae5d772913 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -241,6 +241,13 @@ static bool session_open() { static void session_close() { if (get_sparam(S_FD).to_bool() && (fcntl(get_sparam(S_FD).to_int(), F_GETFD) != -1 || errno != EBADF)) { + struct flock lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); close_safe(get_sparam(S_FD).to_int()); } reset_sparams(); @@ -278,7 +285,19 @@ static bool session_read() { } static bool session_write() { - session_open(); + // rewind the S_FD of the session file + struct flock lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + close_safe(get_sparam(S_FD).to_int()); + set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR, 0777)); + lock.l_type = F_WRLCK; + fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + string data = f$serialize(v$_SESSION.as_array()); ssize_t n = write_safe(get_sparam(S_FD).to_int(), data.c_str(), data.size(), get_sparam(S_PATH).to_string()); if (n < data.size()) { From 99b437f9b176582000dead188de859e7f1b34b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Thu, 11 Jul 2024 06:14:58 +0300 Subject: [PATCH 18/56] focal+gcc-10 and buster+clang --- .github/workflows/Build.yml | 16 +++++++-------- .github/workflows/Dockerfile | 32 +++++++++++++++++++++++++++++ .github/workflows/Dockerfile.buster | 7 +++++-- .github/workflows/Dockerfile.focal | 2 +- 4 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/Dockerfile diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 14c8941479..1a8a23f353 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -25,14 +25,8 @@ jobs: ubsan: off light_runtime: off - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on - - os: buster - compiler: clang++ - cpp: 17 + compiler: clang++-17 + cpp: 20 asan: off ubsan: off light_runtime: on @@ -48,6 +42,12 @@ jobs: asan: on ubsan: off light_runtime: off + - os: focal + compiler: g++-10 + cpp: 20 + asan: off + ubsan: off + light_runtime: on - os: jammy compiler: g++ cpp: 20 diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile new file mode 100644 index 0000000000..b9bae4f653 --- /dev/null +++ b/.github/workflows/Dockerfile @@ -0,0 +1,32 @@ +FROM debian:buster +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y --no-install-recommends apt-utils ca-certificates gnupg wget lsb-release && \ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ + echo "deb https://archive.debian.org/debian buster-backports main" >> /etc/apt/sources.list && \ + echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ + echo "deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ + wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ + echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp buster main" >> /etc/apt/sources.list && \ + wget -qO - https://debian.octopuce.fr/snapshots/sury-php/buster-latest/apt.gpg | apt-key add - && \ + echo "deb https://debian.octopuce.fr/snapshots/sury-php/buster-latest/ buster main" >> /etc/apt/sources.list && \ + TEMP_DEB="$(mktemp)" && \ + wget -O "$TEMP_DEB" 'https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb' && \ + dpkg -i "$TEMP_DEB" && \ + rm -f "$TEMP_DEB" && \ + echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ + wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + git cmake-data=3.18* cmake=3.18* make g++ clang-17 libclang-rt-17-dev gperf netcat \ + python3.7 python3-dev libpython3-dev python3-pip python3-setuptools python3-wheel mysql-server libmysqlclient-dev && \ + pip3 install jsonschema && \ + apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ + libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ + postgresql postgresql-server-dev-all libnuma-dev composer libstdc++6 && \ + rm -rf /var/lib/apt/lists/* && \ + update-alternatives --set php /usr/bin/php7.4 + +RUN useradd -ms /bin/bash kitten diff --git a/.github/workflows/Dockerfile.buster b/.github/workflows/Dockerfile.buster index 432855b3c9..a3d62e1004 100644 --- a/.github/workflows/Dockerfile.buster +++ b/.github/workflows/Dockerfile.buster @@ -5,7 +5,10 @@ COPY tests/python/requirements.txt /tmp/ RUN apt-get update && \ apt-get install -y --no-install-recommends apt-utils ca-certificates gnupg wget lsb-release && \ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ echo "deb https://archive.debian.org/debian buster-backports main" >> /etc/apt/sources.list && \ + echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ + echo "deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp buster main" >> /etc/apt/sources.list && \ wget -qO - https://debian.octopuce.fr/snapshots/sury-php/buster-latest/apt.gpg | apt-key add - && \ @@ -19,12 +22,12 @@ RUN apt-get update && \ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake-data=3.18* cmake=3.18* make g++-10 clang++ gperf netcat \ + git cmake-data=3.18* cmake=3.18* make g++ clang-17 libclang-rt-17-dev gperf netcat \ python3.7 python3-dev libpython3-dev python3-pip python3-setuptools python3-wheel mysql-server libmysqlclient-dev && \ pip3 install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ - postgresql postgresql-server-dev-all libnuma-dev composer && \ + postgresql postgresql-server-dev-all libnuma-dev composer libstdc++6 libc++-6-dev && \ rm -rf /var/lib/apt/lists/* && \ update-alternatives --set php /usr/bin/php7.4 diff --git a/.github/workflows/Dockerfile.focal b/.github/workflows/Dockerfile.focal index 255e51a82d..e3f1cd848a 100644 --- a/.github/workflows/Dockerfile.focal +++ b/.github/workflows/Dockerfile.focal @@ -17,7 +17,7 @@ RUN apt-get update && \ python3.7 -m pip install pip && python3.7 -m pip install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ - postgresql postgresql-server-dev-all libnuma-dev composer unzip && \ + postgresql postgresql-server-dev-all libnuma-dev composer unzip libstdc++6 && \ rm -rf /var/lib/apt/lists/* ENV ASAN_OPTIONS=detect_leaks=0 From 318cfdae98ab325d6bf1c958e5202e72d495d212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 11:45:00 +0300 Subject: [PATCH 19/56] resolve From 7aaf62d068d857f8e22edd9ced4374abff5fa221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 10 Jul 2024 01:18:01 +0300 Subject: [PATCH 20/56] init --- .github/workflows/Build.yml | 34 +++++++++++++++++++++++++++++++--- .github/workflows/debian.yml | 11 +++++++++-- .github/workflows/ubuntu.yml | 23 ++++++++++++++++++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index d3c8d31e5f..820f695dd6 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -23,23 +23,51 @@ jobs: cpp: 17 asan: off ubsan: off + light_runtime: off + - os: buster + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on - os: focal compiler: clang++ cpp: 17 asan: off ubsan: on + light_runtime: off + - os: focal + compiler: clang++ + cpp: 17 + asan: off + ubsan: on + light_runtime: on - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off + light_runtime: off + - os: focal + compiler: g++-10 + cpp: 20 + asan: on + ubsan: off + light_runtime: on - os: jammy compiler: g++ cpp: 20 asan: on ubsan: off - - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" + light_runtime: off + - os: jammy + compiler: g++ + cpp: 20 + asan: on + ubsan: off + light_runtime: on + + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" steps: - uses: actions/checkout@v3 @@ -78,7 +106,7 @@ jobs: - name: Build all run: docker exec kphp-build-container-${{matrix.os}} bash -c - "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" + "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DCOMPILE_RUNTIME_LIGHT=${{matrix.light_runtime}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" - name: Run unit tests run: docker exec kphp-build-container-${{matrix.os}} bash -c diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 2d507d8110..1d365bd178 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -21,8 +21,15 @@ jobs: cpp: 17 asan: off ubsan: off + light_runtime: off + - os: buster + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" steps: - uses: actions/checkout@v3 @@ -59,7 +66,7 @@ jobs: - name: Build all run: docker exec -u kitten kphp-build-container-${{matrix.os}} bash -c - "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" + "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DCOMPILE_RUNTIME_LIGHT=${{matrix.light_runtime}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" - name: Run unit tests run: docker exec -u kitten kphp-build-container-${{matrix.os}} bash -c diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 49af16bd9f..0280b01a48 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,18 +21,39 @@ jobs: cpp: 17 asan: off ubsan: off + light_runtime: off + - os: jammy + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on - os: focal compiler: clang++ cpp: 17 asan: off ubsan: on + light_runtime: off + - os: focal + compiler: clang++ + cpp: 17 + asan: off + ubsan: on + light_runtime: on + - os: focal + compiler: g++-10 + cpp: 20 + asan: on + ubsan: off + light_runtime: off - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off + light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" steps: - uses: actions/checkout@v3 From 66c040f252ce550d05e271561c45ee991be7f707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 10 Jul 2024 01:25:29 +0300 Subject: [PATCH 21/56] temporaly disable buster build die to sury issue --- .github/workflows/Build.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 820f695dd6..65b52c17b1 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -18,18 +18,18 @@ jobs: strategy: matrix: include: - - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: off - - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on + # - os: buster + # compiler: g++ + # cpp: 17 + # asan: off + # ubsan: off + # light_runtime: off + # - os: buster + # compiler: g++ + # cpp: 17 + # asan: off + # ubsan: off + # light_runtime: on - os: focal compiler: clang++ cpp: 17 From ddc5272d0f9575370b65ea4024d7dd6a4478f9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 10 Jul 2024 20:52:04 +0300 Subject: [PATCH 22/56] update --- .github/workflows/Build.yml | 44 +++++++++++------------------ .github/workflows/Dockerfile.buster | 31 -------------------- .github/workflows/debian.yml | 6 ++++ .github/workflows/ubuntu.yml | 23 +-------------- 4 files changed, 23 insertions(+), 81 deletions(-) delete mode 100644 .github/workflows/Dockerfile.buster diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 65b52c17b1..14c8941479 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -18,54 +18,42 @@ jobs: strategy: matrix: include: - # - os: buster - # compiler: g++ - # cpp: 17 - # asan: off - # ubsan: off - # light_runtime: off - # - os: buster - # compiler: g++ - # cpp: 17 - # asan: off - # ubsan: off - # light_runtime: on - - os: focal - compiler: clang++ + - os: buster + compiler: g++ cpp: 17 asan: off - ubsan: on + ubsan: off light_runtime: off - - os: focal + - os: buster + compiler: g++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on + - os: buster compiler: clang++ cpp: 17 asan: off - ubsan: on + ubsan: off light_runtime: on - os: focal - compiler: g++-10 - cpp: 20 - asan: on - ubsan: off + compiler: clang++ + cpp: 17 + asan: off + ubsan: on light_runtime: off - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off - light_runtime: on - - os: jammy - compiler: g++ - cpp: 20 - asan: on - ubsan: off light_runtime: off - os: jammy compiler: g++ cpp: 20 asan: on ubsan: off - light_runtime: on + light_runtime: off name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" diff --git a/.github/workflows/Dockerfile.buster b/.github/workflows/Dockerfile.buster deleted file mode 100644 index c19dd5ef5a..0000000000 --- a/.github/workflows/Dockerfile.buster +++ /dev/null @@ -1,31 +0,0 @@ -FROM debian:buster -ARG DEBIAN_FRONTEND=noninteractive - -COPY tests/python/requirements.txt /tmp/ - -RUN apt-get update && \ - apt-get install -y --no-install-recommends apt-utils ca-certificates gnupg wget lsb-release && \ - echo "deb https://archive.debian.org/debian buster-backports main" >> /etc/apt/sources.list && \ - wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ - echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp buster main" >> /etc/apt/sources.list && \ - wget -qO - https://debian.octopuce.fr/snapshots/sury-php/buster-latest/apt.gpg | apt-key add - && \ - echo "deb https://debian.octopuce.fr/snapshots/sury-php/buster-latest/ buster main" >> /etc/apt/sources.list && \ - TEMP_DEB="$(mktemp)" && \ - wget -O "$TEMP_DEB" 'https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb' && \ - dpkg -i "$TEMP_DEB" && \ - rm -f "$TEMP_DEB" && \ - echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ - wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - git cmake-data=3.18* cmake=3.18* make g++ gperf netcat \ - python3.7 python3-dev libpython3-dev python3-pip python3-setuptools python3-wheel mysql-server libmysqlclient-dev && \ - pip3 install -r /tmp/requirements.txt && \ - apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ - libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ - postgresql postgresql-server-dev-all libnuma-dev composer && \ - rm -rf /var/lib/apt/lists/* && \ - update-alternatives --set php /usr/bin/php7.4 - -RUN useradd -ms /bin/bash kitten diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 1d365bd178..d4c9130881 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -28,6 +28,12 @@ jobs: asan: off ubsan: off light_runtime: on + - os: buster + compiler: clang++ + cpp: 17 + asan: off + ubsan: off + light_runtime: on name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0280b01a48..49af16bd9f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -21,39 +21,18 @@ jobs: cpp: 17 asan: off ubsan: off - light_runtime: off - - os: jammy - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on - os: focal compiler: clang++ cpp: 17 asan: off ubsan: on - light_runtime: off - - os: focal - compiler: clang++ - cpp: 17 - asan: off - ubsan: on - light_runtime: on - - os: focal - compiler: g++-10 - cpp: 20 - asan: on - ubsan: off - light_runtime: off - os: focal compiler: g++-10 cpp: 20 asan: on ubsan: off - light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" steps: - uses: actions/checkout@v3 From 78bee1fc9d464604a3822cfb9cbfd712fac25a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Thu, 11 Jul 2024 06:14:58 +0300 Subject: [PATCH 23/56] focal+gcc-10 and buster+clang --- .github/workflows/Build.yml | 16 +++++++-------- .github/workflows/Dockerfile | 32 ++++++++++++++++++++++++++++++ .github/workflows/Dockerfile.focal | 2 +- 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/Dockerfile diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 14c8941479..1a8a23f353 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -25,14 +25,8 @@ jobs: ubsan: off light_runtime: off - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on - - os: buster - compiler: clang++ - cpp: 17 + compiler: clang++-17 + cpp: 20 asan: off ubsan: off light_runtime: on @@ -48,6 +42,12 @@ jobs: asan: on ubsan: off light_runtime: off + - os: focal + compiler: g++-10 + cpp: 20 + asan: off + ubsan: off + light_runtime: on - os: jammy compiler: g++ cpp: 20 diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile new file mode 100644 index 0000000000..b9bae4f653 --- /dev/null +++ b/.github/workflows/Dockerfile @@ -0,0 +1,32 @@ +FROM debian:buster +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y --no-install-recommends apt-utils ca-certificates gnupg wget lsb-release && \ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ + echo "deb https://archive.debian.org/debian buster-backports main" >> /etc/apt/sources.list && \ + echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ + echo "deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ + wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ + echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp buster main" >> /etc/apt/sources.list && \ + wget -qO - https://debian.octopuce.fr/snapshots/sury-php/buster-latest/apt.gpg | apt-key add - && \ + echo "deb https://debian.octopuce.fr/snapshots/sury-php/buster-latest/ buster main" >> /etc/apt/sources.list && \ + TEMP_DEB="$(mktemp)" && \ + wget -O "$TEMP_DEB" 'https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb' && \ + dpkg -i "$TEMP_DEB" && \ + rm -f "$TEMP_DEB" && \ + echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ + wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + git cmake-data=3.18* cmake=3.18* make g++ clang-17 libclang-rt-17-dev gperf netcat \ + python3.7 python3-dev libpython3-dev python3-pip python3-setuptools python3-wheel mysql-server libmysqlclient-dev && \ + pip3 install jsonschema && \ + apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ + libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ + postgresql postgresql-server-dev-all libnuma-dev composer libstdc++6 && \ + rm -rf /var/lib/apt/lists/* && \ + update-alternatives --set php /usr/bin/php7.4 + +RUN useradd -ms /bin/bash kitten diff --git a/.github/workflows/Dockerfile.focal b/.github/workflows/Dockerfile.focal index 255e51a82d..e3f1cd848a 100644 --- a/.github/workflows/Dockerfile.focal +++ b/.github/workflows/Dockerfile.focal @@ -17,7 +17,7 @@ RUN apt-get update && \ python3.7 -m pip install pip && python3.7 -m pip install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ - postgresql postgresql-server-dev-all libnuma-dev composer unzip && \ + postgresql postgresql-server-dev-all libnuma-dev composer unzip libstdc++6 && \ rm -rf /var/lib/apt/lists/* ENV ASAN_OPTIONS=detect_leaks=0 From a931aa615e53d764c04b3022a92c61fed34f7889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 11:45:00 +0300 Subject: [PATCH 24/56] resolve From 5f9c6b6de27504b31288e429d85044f6dfc2da2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 11:54:04 +0300 Subject: [PATCH 25/56] continue --- .github/workflows/{Dockerfile => Dockerfile.buster} | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) rename .github/workflows/{Dockerfile => Dockerfile.buster} (81%) diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile.buster similarity index 81% rename from .github/workflows/Dockerfile rename to .github/workflows/Dockerfile.buster index b9bae4f653..c19dd5ef5a 100644 --- a/.github/workflows/Dockerfile +++ b/.github/workflows/Dockerfile.buster @@ -1,12 +1,11 @@ FROM debian:buster ARG DEBIAN_FRONTEND=noninteractive +COPY tests/python/requirements.txt /tmp/ + RUN apt-get update && \ apt-get install -y --no-install-recommends apt-utils ca-certificates gnupg wget lsb-release && \ - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ echo "deb https://archive.debian.org/debian buster-backports main" >> /etc/apt/sources.list && \ - echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ - echo "deb-src http://apt.llvm.org/buster/ llvm-toolchain-buster-17 main" >> /etc/apt/sources.list && \ wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp buster main" >> /etc/apt/sources.list && \ wget -qO - https://debian.octopuce.fr/snapshots/sury-php/buster-latest/apt.gpg | apt-key add - && \ @@ -20,12 +19,12 @@ RUN apt-get update && \ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 467B942D3A79BD29 && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake-data=3.18* cmake=3.18* make g++ clang-17 libclang-rt-17-dev gperf netcat \ + git cmake-data=3.18* cmake=3.18* make g++ gperf netcat \ python3.7 python3-dev libpython3-dev python3-pip python3-setuptools python3-wheel mysql-server libmysqlclient-dev && \ - pip3 install jsonschema && \ + pip3 install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ - postgresql postgresql-server-dev-all libnuma-dev composer libstdc++6 && \ + postgresql postgresql-server-dev-all libnuma-dev composer && \ rm -rf /var/lib/apt/lists/* && \ update-alternatives --set php /usr/bin/php7.4 From 1f6928c2114334f00d213ceb603c0893cbc15879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 11:54:57 +0300 Subject: [PATCH 26/56] continue --- .github/workflows/Build.yml | 2 +- .github/workflows/debian.yml | 17 ++--------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 2ac830c5af..d6b3eb4802 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -108,7 +108,7 @@ jobs: - name: Compile dummy PHP script if: ${{matrix.light_runtime}} run: docker exec kphp-build-container-${{matrix.os}} bash -c - "cd ${{env.kphp_build_dir}} && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --mode k2-component --cxx ${{matrix.compiler}} demo.php && kphp_out/cli --user kitten" + "cd ${{env.kphp_build_dir}} && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --mode k2-component --cxx ${{matrix.compiler}} demo.php" - name: Polyfills composer install run: docker exec kphp-build-container-${{matrix.os}} bash -c diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index d4c9130881..2d507d8110 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -21,21 +21,8 @@ jobs: cpp: 17 asan: off ubsan: off - light_runtime: off - - os: buster - compiler: g++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on - - os: buster - compiler: clang++ - cpp: 17 - asan: off - ubsan: off - light_runtime: on - name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}/light_runtime=${{matrix.light_runtime}}" + name: "${{matrix.os}}/${{matrix.compiler}}/c++${{matrix.cpp}}/asan=${{matrix.asan}}/ubsan=${{matrix.ubsan}}" steps: - uses: actions/checkout@v3 @@ -72,7 +59,7 @@ jobs: - name: Build all run: docker exec -u kitten kphp-build-container-${{matrix.os}} bash -c - "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DCOMPILE_RUNTIME_LIGHT=${{matrix.light_runtime}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" + "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" - name: Run unit tests run: docker exec -u kitten kphp-build-container-${{matrix.os}} bash -c From 6500be48a39ccb933697080dde0dcd502ad3e3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 12:33:06 +0300 Subject: [PATCH 27/56] g++-10 option when compiling script --- compiler/compiler-settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index 95f77c5735..71da41c13e 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -312,6 +312,7 @@ void CompilerSettings::init() { ss << " -std=c++17"; #elif __cplusplus <= 202002L ss << " -std=c++20"; + ss << " -fcoroutines"; #else #error unsupported __cplusplus value #endif From ea216c292ba88ef759ee1fc70cbd841a5f502b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 12:44:05 +0300 Subject: [PATCH 28/56] update --- .github/workflows/Build.yml | 2 +- .github/workflows/Dockerfile.focal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index d6b3eb4802..1930066711 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -43,7 +43,7 @@ jobs: ubsan: off light_runtime: off - os: focal - compiler: g++-10 + compiler: g++-11 cpp: 20 asan: off ubsan: off diff --git a/.github/workflows/Dockerfile.focal b/.github/workflows/Dockerfile.focal index 9282166e69..15b1b822fb 100644 --- a/.github/workflows/Dockerfile.focal +++ b/.github/workflows/Dockerfile.focal @@ -15,7 +15,7 @@ RUN apt-get update && \ add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake make clang g++ g++-10 clang-18 libclang-rt-18-dev gperf netcat \ + git cmake make clang g++ g++-10 g++-11 clang-18 libclang-rt-18-dev gperf netcat \ python3.7 python3-pip python3.7-distutils python3.7-dev libpython3.7-dev python3-jsonschema python3-setuptools mysql-server libmysqlclient-dev && \ python3.7 -m pip install pip && python3.7 -m pip install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ From 2bcaf27037493f1ebf13e83c09610faaed78c578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 12:49:36 +0300 Subject: [PATCH 29/56] test --- .github/workflows/Build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 1930066711..bb3c266e31 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -67,7 +67,7 @@ jobs: path: 'kphp-polyfills' - name: Cache docker image - uses: actions/cache@v1 + uses: actions/cache@v3 id: docker-image-cache with: path: /tmp/docker-save @@ -76,7 +76,7 @@ jobs: - name: Build and save docker image if: steps.docker-image-cache.outputs.cache-hit != 'true' run: | - docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} $GITHUB_WORKSPACE -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache + docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} . -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache docker tag kphp-build-img-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache && mkdir -p /tmp/docker-save && docker save kphp-build-img-${{matrix.os}}-cache -o /tmp/docker-save/kphp-build-env-${{matrix.os}}.tar && ls -lh /tmp/docker-save - name: Load docker image from cache From 807e588baaed363f316c0c322a314918ddb19c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 12:49:49 +0300 Subject: [PATCH 30/56] test2 --- .github/workflows/Build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index bb3c266e31..a80ec38f6d 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -76,7 +76,7 @@ jobs: - name: Build and save docker image if: steps.docker-image-cache.outputs.cache-hit != 'true' run: | - docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} . -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache + docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} $GITHUB_WORKSPACE -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache docker tag kphp-build-img-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache && mkdir -p /tmp/docker-save && docker save kphp-build-img-${{matrix.os}}-cache -o /tmp/docker-save/kphp-build-env-${{matrix.os}}.tar && ls -lh /tmp/docker-save - name: Load docker image from cache From d5482a67a7f04272149b9803dfab7df969ef5408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 12:56:30 +0300 Subject: [PATCH 31/56] test --- .github/workflows/Build.yml | 6 +++--- .github/workflows/Dockerfile.focal | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index a80ec38f6d..917d6e75c8 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -43,7 +43,7 @@ jobs: ubsan: off light_runtime: off - os: focal - compiler: g++-11 + compiler: g++-10 cpp: 20 asan: off ubsan: off @@ -67,7 +67,7 @@ jobs: path: 'kphp-polyfills' - name: Cache docker image - uses: actions/cache@v3 + uses: actions/cache@v1 id: docker-image-cache with: path: /tmp/docker-save @@ -76,7 +76,7 @@ jobs: - name: Build and save docker image if: steps.docker-image-cache.outputs.cache-hit != 'true' run: | - docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} $GITHUB_WORKSPACE -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache + docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache docker tag kphp-build-img-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache && mkdir -p /tmp/docker-save && docker save kphp-build-img-${{matrix.os}}-cache -o /tmp/docker-save/kphp-build-env-${{matrix.os}}.tar && ls -lh /tmp/docker-save - name: Load docker image from cache diff --git a/.github/workflows/Dockerfile.focal b/.github/workflows/Dockerfile.focal index 15b1b822fb..9282166e69 100644 --- a/.github/workflows/Dockerfile.focal +++ b/.github/workflows/Dockerfile.focal @@ -15,7 +15,7 @@ RUN apt-get update && \ add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake make clang g++ g++-10 g++-11 clang-18 libclang-rt-18-dev gperf netcat \ + git cmake make clang g++ g++-10 clang-18 libclang-rt-18-dev gperf netcat \ python3.7 python3-pip python3.7-distutils python3.7-dev libpython3.7-dev python3-jsonschema python3-setuptools mysql-server libmysqlclient-dev && \ python3.7 -m pip install pip && python3.7 -m pip install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ From cb09c76a47401f212ab1187efcee4fb529825491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 16 Jul 2024 12:57:59 +0300 Subject: [PATCH 32/56] test --- .github/workflows/Build.yml | 54 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 917d6e75c8..fab9748e39 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -72,11 +72,11 @@ jobs: with: path: /tmp/docker-save key: docker-save-${{matrix.os}}-${{ hashFiles('.github/workflows/Dockerfile.*', 'tests/python/requirements.txt') }} - + - name: Build and save docker image if: steps.docker-image-cache.outputs.cache-hit != 'true' run: | - docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache + docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} $GITHUB_WORKSPACE -t kphp-build-img-${{matrix.os}} --cache-from=kphp-build-img-${{matrix.os}}-cache docker tag kphp-build-img-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache && mkdir -p /tmp/docker-save && docker save kphp-build-img-${{matrix.os}}-cache -o /tmp/docker-save/kphp-build-env-${{matrix.os}}.tar && ls -lh /tmp/docker-save - name: Load docker image from cache @@ -85,7 +85,7 @@ jobs: - name: Start docker container run: | - docker run -dt --name kphp-build-container-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache + docker run -dt --name kphp-build-container-${{matrix.os}} kphp-build-img-${{matrix.os}} docker cp $GITHUB_WORKSPACE/. kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}} - name: Add git safe directory @@ -101,40 +101,40 @@ jobs: "make -C ${{env.kphp_build_dir}} -j$(nproc) test" - name: Compile dummy PHP script - if: ${{!matrix.light_runtime}} + if: ${{matrix.light_runtime}} == off run: docker exec kphp-build-container-${{matrix.os}} bash -c "cd ${{env.kphp_build_dir}} && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --cxx ${{matrix.compiler}} demo.php && kphp_out/server -o --user kitten" - name: Compile dummy PHP script - if: ${{matrix.light_runtime}} + if: ${{matrix.light_runtime}} == on run: docker exec kphp-build-container-${{matrix.os}} bash -c - "cd ${{env.kphp_build_dir}} && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --mode k2-component --cxx ${{matrix.compiler}} demo.php" + "cd ${{env.kphp_build_dir}} && echo "${{matrix.light_runtime}}" && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --mode k2-component --cxx ${{matrix.compiler}} demo.php" - name: Polyfills composer install run: docker exec kphp-build-container-${{matrix.os}} bash -c "composer install -d ${{env.kphp_polyfills_dir}}" - - name: Run python tests - if: ${{!matrix.light_runtime}} - id: python_tests - continue-on-error: true - run: docker exec kphp-build-container-${{matrix.os}} bash -c - "chown -R kitten /home && su kitten -c 'GITHUB_ACTIONS=1 KPHP_TESTS_POLYFILLS_REPO=${{env.kphp_polyfills_dir}} KPHP_CXX=${{matrix.compiler}} python3.7 -m pytest --tb=native -n$(nproc) ${{env.kphp_root_dir}}/tests/python/'" - - - name: Prepare python tests artifacts - if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} - run: docker cp kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}}/tests/python/_tmp/ ${{runner.temp}} && - rm -rf ${{runner.temp}}/_tmp/*/working_dir - - - name: Upload python tests artifacts - uses: actions/upload-artifact@v3 - if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} - with: - path: ${{runner.temp}}/_tmp/ - - - name: Fail pipeline if python tests failed - if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} - run: exit 1 + # - name: Run python tests + # if: ${{!matrix.light_runtime}} + # id: python_tests + # continue-on-error: true + # run: docker exec kphp-build-container-${{matrix.os}} bash -c + # "chown -R kitten /home && su kitten -c 'GITHUB_ACTIONS=1 KPHP_TESTS_POLYFILLS_REPO=${{env.kphp_polyfills_dir}} KPHP_CXX=${{matrix.compiler}} python3.7 -m pytest --tb=native -n$(nproc) ${{env.kphp_root_dir}}/tests/python/'" + + # - name: Prepare python tests artifacts + # if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} + # run: docker cp kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}}/tests/python/_tmp/ ${{runner.temp}} && + # rm -rf ${{runner.temp}}/_tmp/*/working_dir + + # - name: Upload python tests artifacts + # uses: actions/upload-artifact@v3 + # if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} + # with: + # path: ${{runner.temp}}/_tmp/ + + # - name: Fail pipeline if python tests failed + # if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} + # run: exit 1 - name: Remove docker container run: docker rm -f kphp-build-container-${{matrix.os}} From 790db6e73cb86311d3d7335aee5aa71972431ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 14:55:31 +0300 Subject: [PATCH 33/56] fcoroutins flag only with gcc, not with clang --- compiler/compiler-settings.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index 71da41c13e..65411373e1 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -312,7 +312,9 @@ void CompilerSettings::init() { ss << " -std=c++17"; #elif __cplusplus <= 202002L ss << " -std=c++20"; - ss << " -fcoroutines"; + #if (defined(__GNUC__) && !defined(__clang__)) + ss << " -fcoroutines"; + #endif #else #error unsupported __cplusplus value #endif From b611b47e3dec299f47381a1be34a30c2bfd9eb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 15:20:08 +0300 Subject: [PATCH 34/56] move to gcc-11 on focal --- .github/workflows/Build.yml | 2 +- .github/workflows/Dockerfile.focal | 3 ++- cmake/init-compilation-flags.cmake | 3 +-- compiler/compiler-settings.cpp | 4 +--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index fab9748e39..ce5d3e1b26 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -43,7 +43,7 @@ jobs: ubsan: off light_runtime: off - os: focal - compiler: g++-10 + compiler: g++-11 cpp: 20 asan: off ubsan: off diff --git a/.github/workflows/Dockerfile.focal b/.github/workflows/Dockerfile.focal index 9282166e69..76755db75e 100644 --- a/.github/workflows/Dockerfile.focal +++ b/.github/workflows/Dockerfile.focal @@ -7,6 +7,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends apt-utils ca-certificates gnupg wget pkg-config software-properties-common && \ wget -qO /etc/apt/trusted.gpg.d/vkpartner.asc https://artifactory-external.vkpartner.ru/artifactory/api/gpg/key/public && \ wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ + add-apt-repository ppa:ubuntu-toolchain-r/test && \ echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-18 main" >> /etc/apt/sources.list && \ echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-18 main" >> /etc/apt/sources.list && \ echo "deb https://artifactory-external.vkpartner.ru/artifactory/kphp focal main" >> /etc/apt/sources.list && \ @@ -15,7 +16,7 @@ RUN apt-get update && \ add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake make clang g++ g++-10 clang-18 libclang-rt-18-dev gperf netcat \ + git cmake make clang g++ g++-10 g++-11 clang-18 libclang-rt-18-dev gperf netcat \ python3.7 python3-pip python3.7-distutils python3.7-dev libpython3.7-dev python3-jsonschema python3-setuptools mysql-server libmysqlclient-dev && \ python3.7 -m pip install pip && python3.7 -m pip install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ diff --git a/cmake/init-compilation-flags.cmake b/cmake/init-compilation-flags.cmake index 0d18dff157..3d9e39fa78 100644 --- a/cmake/init-compilation-flags.cmake +++ b/cmake/init-compilation-flags.cmake @@ -10,8 +10,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES Clang) set(COMPILER_CLANG True) elseif(CMAKE_CXX_COMPILER_ID MATCHES GNU) if (COMPILE_RUNTIME_LIGHT) - check_compiler_version(gcc 10.1.0) - add_compile_options(-fcoroutines) + check_compiler_version(gcc 11.4.0) else() check_compiler_version(gcc 8.3.0) endif() diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index 65411373e1..1e211d14d9 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -312,9 +312,7 @@ void CompilerSettings::init() { ss << " -std=c++17"; #elif __cplusplus <= 202002L ss << " -std=c++20"; - #if (defined(__GNUC__) && !defined(__clang__)) - ss << " -fcoroutines"; - #endif + ss << "-Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; #else #error unsupported __cplusplus value #endif From f5a4edd6ee0e2b6621657c533db5cb15296d1397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 15:46:39 +0300 Subject: [PATCH 35/56] fix conditions --- .github/workflows/Build.yml | 4 ++-- compiler/compiler-settings.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index ce5d3e1b26..10faf67f72 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -101,12 +101,12 @@ jobs: "make -C ${{env.kphp_build_dir}} -j$(nproc) test" - name: Compile dummy PHP script - if: ${{matrix.light_runtime}} == off + if: matrix.light_runtime == 'off' run: docker exec kphp-build-container-${{matrix.os}} bash -c "cd ${{env.kphp_build_dir}} && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --cxx ${{matrix.compiler}} demo.php && kphp_out/server -o --user kitten" - name: Compile dummy PHP script - if: ${{matrix.light_runtime}} == on + if: matrix.light_runtime == 'on' run: docker exec kphp-build-container-${{matrix.os}} bash -c "cd ${{env.kphp_build_dir}} && echo "${{matrix.light_runtime}}" && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --mode k2-component --cxx ${{matrix.compiler}} demo.php" diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index 1e211d14d9..d19da1e18d 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -312,7 +312,7 @@ void CompilerSettings::init() { ss << " -std=c++17"; #elif __cplusplus <= 202002L ss << " -std=c++20"; - ss << "-Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; + ss << " -Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; #else #error unsupported __cplusplus value #endif From 8d194f1be6841c1409049fb72f183d0148a9d364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 15:46:39 +0300 Subject: [PATCH 36/56] fix conditions --- .github/workflows/Build.yml | 4 ++-- cmake/init-compilation-flags.cmake | 1 + compiler/compiler-settings.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index ce5d3e1b26..10faf67f72 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -101,12 +101,12 @@ jobs: "make -C ${{env.kphp_build_dir}} -j$(nproc) test" - name: Compile dummy PHP script - if: ${{matrix.light_runtime}} == off + if: matrix.light_runtime == 'off' run: docker exec kphp-build-container-${{matrix.os}} bash -c "cd ${{env.kphp_build_dir}} && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --cxx ${{matrix.compiler}} demo.php && kphp_out/server -o --user kitten" - name: Compile dummy PHP script - if: ${{matrix.light_runtime}} == on + if: matrix.light_runtime == 'on' run: docker exec kphp-build-container-${{matrix.os}} bash -c "cd ${{env.kphp_build_dir}} && echo "${{matrix.light_runtime}}" && echo 'hello world' > demo.php && ${{env.kphp_root_dir}}/objs/bin/kphp2cpp --mode k2-component --cxx ${{matrix.compiler}} demo.php" diff --git a/cmake/init-compilation-flags.cmake b/cmake/init-compilation-flags.cmake index 3d9e39fa78..0cbb1355f4 100644 --- a/cmake/init-compilation-flags.cmake +++ b/cmake/init-compilation-flags.cmake @@ -106,6 +106,7 @@ endif() add_compile_options(-Werror -Wall -Wextra -Wunused-function -Wfloat-conversion -Wno-sign-compare -Wuninitialized -Wno-redundant-move -Wno-missing-field-initializers) if(COMPILE_RUNTIME_LIGHT) + add_compile_options(-fPIC) add_compile_options(-Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes) add_compile_options(-Wno-vla-extension) endif() diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index 1e211d14d9..d19da1e18d 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -312,7 +312,7 @@ void CompilerSettings::init() { ss << " -std=c++17"; #elif __cplusplus <= 202002L ss << " -std=c++20"; - ss << "-Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; + ss << " -Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; #else #error unsupported __cplusplus value #endif From 6c495653ef48f8dcb040ca0f52d3161e2faeefb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 16:37:59 +0300 Subject: [PATCH 37/56] try fix cache --- .github/workflows/Build.yml | 56 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 10faf67f72..0131dbe5cb 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -70,24 +70,24 @@ jobs: uses: actions/cache@v1 id: docker-image-cache with: - path: /tmp/docker-save + path: /tmp/docker-save-${{matrix.os}} key: docker-save-${{matrix.os}}-${{ hashFiles('.github/workflows/Dockerfile.*', 'tests/python/requirements.txt') }} - + - name: Build and save docker image if: steps.docker-image-cache.outputs.cache-hit != 'true' run: | - docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} $GITHUB_WORKSPACE -t kphp-build-img-${{matrix.os}} --cache-from=kphp-build-img-${{matrix.os}}-cache - docker tag kphp-build-img-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache && mkdir -p /tmp/docker-save && docker save kphp-build-img-${{matrix.os}}-cache -o /tmp/docker-save/kphp-build-env-${{matrix.os}}.tar && ls -lh /tmp/docker-save + docker build -f $GITHUB_WORKSPACE/.github/workflows/Dockerfile.${{matrix.os}} $GITHUB_WORKSPACE -t kphp-build-img-${{matrix.os}} --cache-from=type=local,src=kphp-build-img-${{matrix.os}}-cache + docker tag kphp-build-img-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache && mkdir -p /tmp/docker-save-${{matrix.os}} && docker save kphp-build-img-${{matrix.os}}-cache -o /tmp/docker-save-${{matrix.os}}/kphp-build-env-${{matrix.os}}.tar && ls -lh /tmp/docker-save-${{matrix.os}} - name: Load docker image from cache if: steps.docker-image-cache.outputs.cache-hit == 'true' - run: docker load --input /tmp/docker-save/kphp-build-env-${{matrix.os}}.tar + run: docker load --input /tmp/docker-save-${{matrix.os}}/kphp-build-env-${{matrix.os}}.tar - name: Start docker container run: | - docker run -dt --name kphp-build-container-${{matrix.os}} kphp-build-img-${{matrix.os}} + docker run -dt --name kphp-build-container-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache docker cp $GITHUB_WORKSPACE/. kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}} - + - name: Add git safe directory run: docker exec kphp-build-container-${{matrix.os}} bash -c "git config --global --add safe.directory ${{env.kphp_root_dir}}" @@ -114,27 +114,27 @@ jobs: run: docker exec kphp-build-container-${{matrix.os}} bash -c "composer install -d ${{env.kphp_polyfills_dir}}" - # - name: Run python tests - # if: ${{!matrix.light_runtime}} - # id: python_tests - # continue-on-error: true - # run: docker exec kphp-build-container-${{matrix.os}} bash -c - # "chown -R kitten /home && su kitten -c 'GITHUB_ACTIONS=1 KPHP_TESTS_POLYFILLS_REPO=${{env.kphp_polyfills_dir}} KPHP_CXX=${{matrix.compiler}} python3.7 -m pytest --tb=native -n$(nproc) ${{env.kphp_root_dir}}/tests/python/'" - - # - name: Prepare python tests artifacts - # if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} - # run: docker cp kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}}/tests/python/_tmp/ ${{runner.temp}} && - # rm -rf ${{runner.temp}}/_tmp/*/working_dir - - # - name: Upload python tests artifacts - # uses: actions/upload-artifact@v3 - # if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} - # with: - # path: ${{runner.temp}}/_tmp/ - - # - name: Fail pipeline if python tests failed - # if: ${{ (steps.python_tests.outcome == 'failure') && (!matrix.light_runtime) }} - # run: exit 1 + - name: Run python tests + if: matrix.light_runtime == 'off' + id: python_tests + continue-on-error: true + run: docker exec kphp-build-container-${{matrix.os}} bash -c + "chown -R kitten /home && su kitten -c 'GITHUB_ACTIONS=1 KPHP_TESTS_POLYFILLS_REPO=${{env.kphp_polyfills_dir}} KPHP_CXX=${{matrix.compiler}} python3.7 -m pytest --tb=native -n$(nproc) ${{env.kphp_root_dir}}/tests/python/'" + + - name: Prepare python tests artifacts + if: ${{ (steps.python_tests.outcome == 'failure') && matrix.light_runtime == 'off' }} + run: docker cp kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}}/tests/python/_tmp/ ${{runner.temp}} && + rm -rf ${{runner.temp}}/_tmp/*/working_dir + + - name: Upload python tests artifacts + uses: actions/upload-artifact@v3 + if: ${{ (steps.python_tests.outcome == 'failure') && matrix.light_runtime == 'off' }} + with: + path: ${{runner.temp}}/_tmp/ + + - name: Fail pipeline if python tests failed + if: ${{ (steps.python_tests.outcome == 'failure') && matrix.light_runtime == 'off' }} + run: exit 1 - name: Remove docker container run: docker rm -f kphp-build-container-${{matrix.os}} From bf88ac2078623e8add9f1fadf942709d5bbe4cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 17:42:41 +0300 Subject: [PATCH 38/56] light runtime fpic --- cmake/init-compilation-flags.cmake | 1 - runtime-light/runtime-light.cmake | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/init-compilation-flags.cmake b/cmake/init-compilation-flags.cmake index 0cbb1355f4..3d9e39fa78 100644 --- a/cmake/init-compilation-flags.cmake +++ b/cmake/init-compilation-flags.cmake @@ -106,7 +106,6 @@ endif() add_compile_options(-Werror -Wall -Wextra -Wunused-function -Wfloat-conversion -Wno-sign-compare -Wuninitialized -Wno-redundant-move -Wno-missing-field-initializers) if(COMPILE_RUNTIME_LIGHT) - add_compile_options(-fPIC) add_compile_options(-Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes) add_compile_options(-Wno-vla-extension) endif() diff --git a/runtime-light/runtime-light.cmake b/runtime-light/runtime-light.cmake index c8d6d1c831..37db0aa5d7 100644 --- a/runtime-light/runtime-light.cmake +++ b/runtime-light/runtime-light.cmake @@ -30,7 +30,10 @@ set_target_properties(runtime-light PROPERTIES vk_add_library(kphp-light-runtime STATIC) target_link_libraries(kphp-light-runtime PUBLIC vk::light_common vk::runtime-light vk::runtime-core) -set_target_properties(kphp-light-runtime PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${OBJS_DIR}) +set_target_properties(kphp-light-runtime PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${OBJS_DIR} + POSITION_INDEPENDENT_CODE ON +) file(GLOB_RECURSE KPHP_RUNTIME_ALL_HEADERS RELATIVE ${BASE_DIR} From e8fd52f2fc4efaf568a195c8ec33a0120d72e14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 17:46:46 +0300 Subject: [PATCH 39/56] cleanup --- .github/workflows/Build.yml | 9 +++++++-- .github/workflows/Dockerfile.focal | 4 ++-- runtime-core/runtime-core.cmake | 1 + runtime-light/runtime-light.cmake | 5 +---- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 0131dbe5cb..517a800a32 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -67,7 +67,7 @@ jobs: path: 'kphp-polyfills' - name: Cache docker image - uses: actions/cache@v1 + uses: actions/cache@v3 id: docker-image-cache with: path: /tmp/docker-save-${{matrix.os}} @@ -87,11 +87,16 @@ jobs: run: | docker run -dt --name kphp-build-container-${{matrix.os}} kphp-build-img-${{matrix.os}}-cache docker cp $GITHUB_WORKSPACE/. kphp-build-container-${{matrix.os}}:${{env.kphp_root_dir}} - + - name: Add git safe directory run: docker exec kphp-build-container-${{matrix.os}} bash -c "git config --global --add safe.directory ${{env.kphp_root_dir}}" + - name: Check formatting in light runtime folder + if: ${{ matrix.os == 'focal' && matrix.light_runtime == 'on' }} + run: docker exec kphp-build-container-${{matrix.os}} bash -c + "find ${{env.kphp_root_dir}}/runtime-light/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format-18 -—dry-run -Werror" + - name: Build all run: docker exec kphp-build-container-${{matrix.os}} bash -c "cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DCOMPILE_RUNTIME_LIGHT=${{matrix.light_runtime}} -DADDRESS_SANITIZER=${{matrix.asan}} -DUNDEFINED_SANITIZER=${{matrix.ubsan}} -DPDO_DRIVER_MYSQL=ON -DPDO_DRIVER_PGSQL=ON -DPDO_LIBS_STATIC_LINKING=ON -S ${{env.kphp_root_dir}} -B ${{env.kphp_build_dir}} && make -C ${{env.kphp_build_dir}} -j$(nproc) all" diff --git a/.github/workflows/Dockerfile.focal b/.github/workflows/Dockerfile.focal index 76755db75e..8df13e0327 100644 --- a/.github/workflows/Dockerfile.focal +++ b/.github/workflows/Dockerfile.focal @@ -16,12 +16,12 @@ RUN apt-get update && \ add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && \ apt-get install -y --no-install-recommends \ - git cmake make clang g++ g++-10 g++-11 clang-18 libclang-rt-18-dev gperf netcat \ + git cmake make clang g++ g++-10 g++-11 clang-18 libclang-rt-18-dev clang-format-18 gperf netcat \ python3.7 python3-pip python3.7-distutils python3.7-dev libpython3.7-dev python3-jsonschema python3-setuptools mysql-server libmysqlclient-dev && \ python3.7 -m pip install pip && python3.7 -m pip install -r /tmp/requirements.txt && \ apt-get install -y --no-install-recommends curl-kphp-vk kphp-timelib libuber-h3-dev libfmt-dev libgtest-dev libgmock-dev libre2-dev libpcre3-dev \ libzstd-dev libyaml-cpp-dev libnghttp2-dev zlib1g-dev php7.4-dev libldap-dev libkrb5-dev \ - postgresql postgresql-server-dev-all libnuma-dev composer unzip libstdc++6 && \ + postgresql postgresql-server-dev-all libnuma-dev composer unzip && \ rm -rf /var/lib/apt/lists/* ENV ASAN_OPTIONS=detect_leaks=0 diff --git a/runtime-core/runtime-core.cmake b/runtime-core/runtime-core.cmake index be50be3f42..b43df8dcfd 100644 --- a/runtime-core/runtime-core.cmake +++ b/runtime-core/runtime-core.cmake @@ -23,3 +23,4 @@ set(KPHP_CORE_SRC ) vk_add_library(runtime-core OBJECT ${KPHP_CORE_SRC}) +set_property(TARGET runtime-core PROPERTY POSITION_INDEPENDENT_CODE ON) \ No newline at end of file diff --git a/runtime-light/runtime-light.cmake b/runtime-light/runtime-light.cmake index 37db0aa5d7..c8d6d1c831 100644 --- a/runtime-light/runtime-light.cmake +++ b/runtime-light/runtime-light.cmake @@ -30,10 +30,7 @@ set_target_properties(runtime-light PROPERTIES vk_add_library(kphp-light-runtime STATIC) target_link_libraries(kphp-light-runtime PUBLIC vk::light_common vk::runtime-light vk::runtime-core) -set_target_properties(kphp-light-runtime PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${OBJS_DIR} - POSITION_INDEPENDENT_CODE ON -) +set_target_properties(kphp-light-runtime PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${OBJS_DIR}) file(GLOB_RECURSE KPHP_RUNTIME_ALL_HEADERS RELATIVE ${BASE_DIR} From 32d1a2458b7d923d052ebe2183064822b3f51106 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 17 Jul 2024 18:46:13 +0300 Subject: [PATCH 40/56] format code --- runtime-light/header.h | 17 ++---- runtime-light/utils/json-functions.cpp | 66 ++++++++++-------------- runtime-light/utils/json-functions.h | 29 +++++------ runtime-light/utils/panic.h | 6 +-- runtime-light/utils/php_assert.h | 2 +- runtime-light/utils/to-array-processor.h | 4 +- 6 files changed, 53 insertions(+), 71 deletions(-) diff --git a/runtime-light/header.h b/runtime-light/header.h index 5bae9daf93..d513554a0f 100644 --- a/runtime-light/header.h +++ b/runtime-light/header.h @@ -107,8 +107,7 @@ struct PlatformCtx { * `stream_d` will be assigned `0`. * however `stream_d=0` itself is not an error marker */ - enum OpenStreamResult (*open)(size_t name_len, const char *name, - uint64_t *stream_d); + enum OpenStreamResult (*open)(size_t name_len, const char *name, uint64_t *stream_d); /* * If the write or read status is `Blocked` - then the platform ensures that * the component receives this `stream_d` via `take_update` when the status is @@ -118,8 +117,7 @@ struct PlatformCtx { * `new_status` will be assigned as * `{.read_status = 0, .write_status = 0, .please_shutdown = 0}`. */ - enum GetStatusResult (*get_stream_status)(uint64_t stream_d, - struct StreamStatus *new_status); + enum GetStatusResult (*get_stream_status)(uint64_t stream_d, struct StreamStatus *new_status); /* * Return processed bytes (written or read). * Guaranteed to return `0` if the stream is `Closed`, `Blocked` or @@ -190,8 +188,7 @@ struct PlatformCtx { * * `deadline` will be assigned `0` if `timer_d` invalid */ - enum TimerStatus (*get_timer_status)(uint64_t timer_d, - struct TimePoint *deadline); + enum TimerStatus (*get_timer_status)(uint64_t timer_d, struct TimePoint *deadline); /* * Return: `bool`. * If `True`: the update was successfully received. @@ -262,15 +259,11 @@ struct ImageInfo { }; // Every image should provide these symbols -enum PollStatus vk_k2_poll(const struct ImageState *image_state, - const struct PlatformCtx *pt_ctx, - struct ComponentState *component_ctx); +enum PollStatus vk_k2_poll(const struct ImageState *image_state, const struct PlatformCtx *pt_ctx, struct ComponentState *component_ctx); // platform_ctx without IO stuff (nullptr instead io-functions) // for now, returning nullptr will indicate error -struct ComponentState * -vk_k2_create_component_state(const struct ImageState *image_state, - const struct PlatformCtx *pt_ctx); +struct ComponentState *vk_k2_create_component_state(const struct ImageState *image_state, const struct PlatformCtx *pt_ctx); // platform_ctx without IO stuff (nullptr instead io-functions) // for now, returning nullptr will indicate error diff --git a/runtime-light/utils/json-functions.cpp b/runtime-light/utils/json-functions.cpp index 5fde8e0723..58d88c05a2 100644 --- a/runtime-light/utils/json-functions.cpp +++ b/runtime-light/utils/json-functions.cpp @@ -7,13 +7,13 @@ #include "common/algorithms/find.h" #include "runtime-light/component/component.h" // -//#include "runtime/string_functions.h" +// #include "runtime/string_functions.h" // note: json-functions.cpp is used for non-typed json implementation: for json_encode() and json_decode() // for classes, e.g. `JsonEncoder::encode(new A)`, see json-writer.cpp and from/to visitors namespace { -void json_append_one_char(unsigned int c, string_buffer & sb) noexcept { +void json_append_one_char(unsigned int c, string_buffer &sb) noexcept { sb.append_char('\\'); sb.append_char('u'); sb.append_char("0123456789abcdef"[c >> 12]); @@ -22,7 +22,7 @@ void json_append_one_char(unsigned int c, string_buffer & sb) noexcept { sb.append_char("0123456789abcdef"[c & 15]); } -bool json_append_char(unsigned int c, string_buffer & sb) noexcept { +bool json_append_char(unsigned int c, string_buffer &sb) noexcept { if (c < 0x10000) { if (0xD7FF < c && c < 0xE000) { return false; @@ -39,8 +39,7 @@ bool json_append_char(unsigned int c, string_buffer & sb) noexcept { return false; } - -bool do_json_encode_string_php(const JsonPath &json_path, const char *s, int len, int64_t options, string_buffer & sb) noexcept { +bool do_json_encode_string_php(const JsonPath &json_path, const char *s, int len, int64_t options, string_buffer &sb) noexcept { int begin_pos = sb.size(); if (options & JSON_UNESCAPED_UNICODE) { sb.reserve(2 * len + 2); @@ -178,7 +177,7 @@ string JsonPath::to_string() const { } unsigned num_parts = std::clamp(depth, 0U, static_cast(arr.size())); string result; - result.reserve_at_least((num_parts+1) * 8); + result.reserve_at_least((num_parts + 1) * 8); result.push_back('/'); for (unsigned i = 0; i < num_parts; i++) { const char *key = arr[i]; @@ -200,13 +199,12 @@ string JsonPath::to_string() const { namespace impl_ { -JsonEncoder::JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key) noexcept: - options_(options), - simple_encode_(simple_encode), - json_obj_magic_key_(json_obj_magic_key) { -} +JsonEncoder::JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key) noexcept + : options_(options) + , simple_encode_(simple_encode) + , json_obj_magic_key_(json_obj_magic_key) {} -bool JsonEncoder::encode(bool b, string_buffer & sb) noexcept { +bool JsonEncoder::encode(bool b, string_buffer &sb) noexcept { if (b) { sb.append("true", 4); } else { @@ -215,17 +213,17 @@ bool JsonEncoder::encode(bool b, string_buffer & sb) noexcept { return true; } -bool JsonEncoder::encode_null(string_buffer & sb) const noexcept { +bool JsonEncoder::encode_null(string_buffer &sb) const noexcept { sb.append("null", 4); return true; } -bool JsonEncoder::encode(int64_t i, string_buffer & sb) noexcept { +bool JsonEncoder::encode(int64_t i, string_buffer &sb) noexcept { sb << i; return true; } -bool JsonEncoder::encode(double d, string_buffer & sb) noexcept { +bool JsonEncoder::encode(double d, string_buffer &sb) noexcept { if (vk::any_of_equal(std::fpclassify(d), FP_INFINITE, FP_NAN)) { php_warning("%s: strange double %lf in function json_encode", json_path_.to_string().c_str(), d); if (options_ & JSON_PARTIAL_OUTPUT_ON_ERROR) { @@ -234,17 +232,17 @@ bool JsonEncoder::encode(double d, string_buffer & sb) noexcept { return false; } } else { - //todo:k2 implement f$number_format - sb << /*(simple_encode_ ? f$number_format(d, 6, string{"."}, string{}) : */ string{d}/*)*/; + // todo:k2 implement f$number_format + sb << /*(simple_encode_ ? f$number_format(d, 6, string{"."}, string{}) : */ string{d} /*)*/; } return true; } -bool JsonEncoder::encode(const string &s, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const string &s, string_buffer &sb) noexcept { return do_json_encode_string_php(json_path_, s.c_str(), s.size(), options_, sb); } -bool JsonEncoder::encode(const mixed &v, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const mixed &v, string_buffer &sb) noexcept { switch (v.get_type()) { case mixed::type::NUL: return encode_null(sb); @@ -280,29 +278,22 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json json_skip_blanks(s, i); switch (s[i]) { case 'n': - if (s[i + 1] == 'u' && - s[i + 2] == 'l' && - s[i + 3] == 'l') { + if (s[i + 1] == 'u' && s[i + 2] == 'l' && s[i + 3] == 'l') { i += 4; return true; } break; case 't': - if (s[i + 1] == 'r' && - s[i + 2] == 'u' && - s[i + 3] == 'e') { + if (s[i + 1] == 'r' && s[i + 2] == 'u' && s[i + 3] == 'e') { i += 4; - new(&v) mixed(true); + new (&v) mixed(true); return true; } break; case 'f': - if (s[i + 1] == 'a' && - s[i + 2] == 'l' && - s[i + 3] == 's' && - s[i + 4] == 'e') { + if (s[i + 1] == 'a' && s[i + 2] == 'l' && s[i + 3] == 's' && s[i + 4] == 'e') { i += 5; - new(&v) mixed(false); + new (&v) mixed(false); return true; } break; @@ -364,8 +355,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json } if (0xD7FF < num && num < 0xE000) { - if (s[i + 1] == '\\' && s[i + 2] == 'u' && - isxdigit(s[i + 3]) && isxdigit(s[i + 4]) && isxdigit(s[i + 5]) && isxdigit(s[i + 6])) { + if (s[i + 1] == '\\' && s[i + 2] == 'u' && isxdigit(s[i + 3]) && isxdigit(s[i + 4]) && isxdigit(s[i + 5]) && isxdigit(s[i + 6])) { i += 2; int u = 0; for (int t = 0; t < 4; t++) { @@ -419,7 +409,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json } value.shrink(l); - new(&v) mixed(value); + new (&v) mixed(value); i++; return true; } @@ -446,7 +436,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json i++; } - new(&v) mixed(res); + new (&v) mixed(res); return true; } case '{': { @@ -483,7 +473,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json res[string{json_obj_magic_key}] = true; } - new(&v) mixed(res); + new (&v) mixed(res); return true; } default: { @@ -495,7 +485,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json int64_t intval = 0; if (php_try_to_int(s + i, j - i, &intval)) { i = j; - new(&v) mixed(intval); + new (&v) mixed(intval); return true; } @@ -503,7 +493,7 @@ bool do_json_decode(const char *s, int s_len, int &i, mixed &v, const char *json double floatval = strtod(s + i, &end_ptr); if (end_ptr == s + j) { i = j; - new(&v) mixed(floatval); + new (&v) mixed(floatval); return true; } } diff --git a/runtime-light/utils/json-functions.h b/runtime-light/utils/json-functions.h index 15626a7e23..7805da79d9 100644 --- a/runtime-light/utils/json-functions.h +++ b/runtime-light/utils/json-functions.h @@ -9,7 +9,6 @@ #include "common/mixin/not_copyable.h" #include "runtime-core/runtime-core.h" - constexpr int64_t JSON_UNESCAPED_UNICODE = 1; constexpr int64_t JSON_FORCE_OBJECT = 16; constexpr int64_t JSON_PRETTY_PRINT = 128; // TODO: add actual support to untyped @@ -22,7 +21,7 @@ constexpr int64_t JSON_AVAILABLE_FLAGS_TYPED = JSON_PRETTY_PRINT | JSON_PRESERVE struct JsonPath { constexpr static int MAX_DEPTH = 8; - std::array arr; + std::array arr; unsigned depth = 0; void enter(const char *key) noexcept { @@ -47,31 +46,31 @@ class JsonEncoder : vk::not_copyable { public: JsonEncoder(int64_t options, bool simple_encode, const char *json_obj_magic_key = nullptr) noexcept; - //todo:k2 change static_SB everywhere to string_buffer arg - bool encode(bool b, string_buffer & sb) noexcept; - bool encode(int64_t i, string_buffer & sb) noexcept; - bool encode(const string &s, string_buffer & sb) noexcept; - bool encode(double d, string_buffer & sb) noexcept; - bool encode(const mixed &v, string_buffer & sb) noexcept; + // todo:k2 change static_SB everywhere to string_buffer arg + bool encode(bool b, string_buffer &sb) noexcept; + bool encode(int64_t i, string_buffer &sb) noexcept; + bool encode(const string &s, string_buffer &sb) noexcept; + bool encode(double d, string_buffer &sb) noexcept; + bool encode(const mixed &v, string_buffer &sb) noexcept; template - bool encode(const array &arr, string_buffer & sb) noexcept; + bool encode(const array &arr, string_buffer &sb) noexcept; template - bool encode(const Optional &opt, string_buffer & sb) noexcept; + bool encode(const Optional &opt, string_buffer &sb) noexcept; private: - bool encode_null(string_buffer & sb) const noexcept; + bool encode_null(string_buffer &sb) const noexcept; JsonPath json_path_; const int64_t options_{0}; - //todo:k2 use simple_encode + // todo:k2 use simple_encode [[maybe_unused]] const bool simple_encode_{false}; const char *json_obj_magic_key_{nullptr}; }; template -bool JsonEncoder::encode(const array &arr, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const array &arr, string_buffer &sb) noexcept { bool is_vector = arr.is_vector(); const bool force_object = static_cast(JSON_FORCE_OBJECT & options_); if (!force_object && !is_vector && arr.is_pseudo_vector()) { @@ -142,7 +141,7 @@ bool JsonEncoder::encode(const array &arr, string_buffer & sb) noexcept { } template -bool JsonEncoder::encode(const Optional &opt, string_buffer & sb) noexcept { +bool JsonEncoder::encode(const Optional &opt, string_buffer &sb) noexcept { switch (opt.value_state()) { case OptionalState::has_value: return encode(opt.val(), sb); @@ -170,7 +169,7 @@ Optional f$json_encode(const T &v, int64_t options = 0, bool simple_enco return sb.c_str(); } -//todo:k2 implement string f$vk_json_encode_safe(const T &v, bool simple_encode = true) noexcept +// todo:k2 implement string f$vk_json_encode_safe(const T &v, bool simple_encode = true) noexcept template inline Optional f$vk_json_encode(const T &v) noexcept { diff --git a/runtime-light/utils/panic.h b/runtime-light/utils/panic.h index d11fbed624..7dfe5e956a 100644 --- a/runtime-light/utils/panic.h +++ b/runtime-light/utils/panic.h @@ -11,9 +11,9 @@ #include "runtime-light/utils/logs.h" inline void critical_error_handler() { - constexpr const char * message = "script panic"; - const PlatformCtx & ptx = *get_platform_context(); - ComponentState & ctx = *get_component_context(); + constexpr const char *message = "script panic"; + const PlatformCtx &ptx = *get_platform_context(); + ComponentState &ctx = *get_component_context(); ptx.log(Debug, strlen(message), message); if (ctx.not_finished()) { diff --git a/runtime-light/utils/php_assert.h b/runtime-light/utils/php_assert.h index 41d30d4f7b..81d534e5dd 100644 --- a/runtime-light/utils/php_assert.h +++ b/runtime-light/utils/php_assert.h @@ -7,7 +7,7 @@ #include #include -#include "common/wrappers/likely.h" #include "common/mixin/not_copyable.h" +#include "common/wrappers/likely.h" #include "runtime-core/utils/kphp-assert-core.h" diff --git a/runtime-light/utils/to-array-processor.h b/runtime-light/utils/to-array-processor.h index 19ac809395..47ff7ec4a2 100644 --- a/runtime-light/utils/to-array-processor.h +++ b/runtime-light/utils/to-array-processor.h @@ -86,7 +86,7 @@ class ToArrayVisitor { add_value(field_name, instance.is_null() ? mixed{} : f$to_array_debug(instance, with_class_names_)); } - template + template void process_impl(const char *field_name, const std::tuple &value) { ToArrayVisitor tuple_processor{with_class_names_}; tuple_processor.result_.reserve(sizeof...(Args), true); @@ -95,7 +95,7 @@ class ToArrayVisitor { add_value(field_name, std::move(tuple_processor).flush_result()); } - template + template void process_impl(const char *field_name, const shape, T...> &value) { ToArrayVisitor shape_processor{with_class_names_}; shape_processor.result_.reserve(sizeof...(Is), true); From 92ccc80db72e9e79c82ac111d286394086956c4e Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 17 Jul 2024 18:53:04 +0300 Subject: [PATCH 41/56] remove less `-` in dry-run --- .github/workflows/Build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 517a800a32..7b12acad0c 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -95,7 +95,7 @@ jobs: - name: Check formatting in light runtime folder if: ${{ matrix.os == 'focal' && matrix.light_runtime == 'on' }} run: docker exec kphp-build-container-${{matrix.os}} bash -c - "find ${{env.kphp_root_dir}}/runtime-light/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format-18 -—dry-run -Werror" + "find ${{env.kphp_root_dir}}/runtime-light/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format-18 --dry-run -Werror" - name: Build all run: docker exec kphp-build-container-${{matrix.os}} bash -c From 4675969848496e6d2033f1e58f922514ba05fe93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 19:37:16 +0300 Subject: [PATCH 42/56] fix macos gh build --- .github/workflows/Build.yml | 2 +- cmake/init-compilation-flags.cmake | 2 +- runtime-core/runtime-core.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 7b12acad0c..9828eb9005 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -170,7 +170,7 @@ jobs: brew update brew install re2c cmake coreutils openssl libiconv re2 pcre yaml-cpp zstd googletest shivammathur/php/php@7.4 brew link --overwrite --force shivammathur/php/php@7.4 - /usr/local/Frameworks/Python.framework/Versions/3.12/bin/python3.12 -m pip install --upgrade pip --break-system-packages && /usr/local/Frameworks/Python.framework/Versions/3.12/bin/pip3 install jsonschema install --break-system-packages jsonschema + /usr/local/Frameworks/Python.framework/Versions/3.12/bin/python3.12 -m pip install --upgrade pip --break-system-packages && /usr/local/Frameworks/Python.framework/Versions/3.12/bin/pip3 install --break-system-packages jsonschema - name: Run cmake run: cmake -DCMAKE_CXX_COMPILER=${{matrix.compiler}} -DCMAKE_CXX_STANDARD=${{matrix.cpp}} -DDOWNLOAD_MISSING_LIBRARIES=On -S $GITHUB_WORKSPACE -B ${{runner.workspace}}/build diff --git a/cmake/init-compilation-flags.cmake b/cmake/init-compilation-flags.cmake index 3d9e39fa78..2729df9cd3 100644 --- a/cmake/init-compilation-flags.cmake +++ b/cmake/init-compilation-flags.cmake @@ -141,4 +141,4 @@ if(COMPILE_RUNTIME_LIGHT) message(FATAL_ERROR "Compiler or libstdc++ does not support coroutines") endif() file(REMOVE "${PROJECT_BINARY_DIR}/check_coroutine_include.cpp") -endif() \ No newline at end of file +endif() diff --git a/runtime-core/runtime-core.cmake b/runtime-core/runtime-core.cmake index b43df8dcfd..c2cd5ecdb4 100644 --- a/runtime-core/runtime-core.cmake +++ b/runtime-core/runtime-core.cmake @@ -23,4 +23,4 @@ set(KPHP_CORE_SRC ) vk_add_library(runtime-core OBJECT ${KPHP_CORE_SRC}) -set_property(TARGET runtime-core PROPERTY POSITION_INDEPENDENT_CODE ON) \ No newline at end of file +set_property(TARGET runtime-core PROPERTY POSITION_INDEPENDENT_CODE ON) From 937d928b48960b888a3d10640646563ab3449b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=83=D1=82=D1=8E=D0=BD=D1=8F=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 17 Jul 2024 21:28:26 +0300 Subject: [PATCH 43/56] remove -Wno-unused-result flag --- cmake/init-compilation-flags.cmake | 2 +- common/dl-utils-lite.cpp | 9 +++++---- compiler/compiler-settings.cpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmake/init-compilation-flags.cmake b/cmake/init-compilation-flags.cmake index 2729df9cd3..268b0cda29 100644 --- a/cmake/init-compilation-flags.cmake +++ b/cmake/init-compilation-flags.cmake @@ -106,7 +106,7 @@ endif() add_compile_options(-Werror -Wall -Wextra -Wunused-function -Wfloat-conversion -Wno-sign-compare -Wuninitialized -Wno-redundant-move -Wno-missing-field-initializers) if(COMPILE_RUNTIME_LIGHT) - add_compile_options(-Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes) + add_compile_options(-Wno-type-limits -Wno-attributes -Wno-ignored-attributes) add_compile_options(-Wno-vla-extension) endif() diff --git a/common/dl-utils-lite.cpp b/common/dl-utils-lite.cpp index 8648274d6c..6bf9d35218 100644 --- a/common/dl-utils-lite.cpp +++ b/common/dl-utils-lite.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -49,9 +50,9 @@ double dl_time() { } void dl_print_backtrace(void **trace, int trace_size) { - write (2, "\n------- Stack Backtrace -------\n", 33); + std::ignore = write (2, "\n------- Stack Backtrace -------\n", 33); backtrace_symbols_fd (trace, trace_size, 2); - write (2, "-------------------------------\n", 32); + std::ignore = write (2, "-------------------------------\n", 32); } void dl_print_backtrace() { @@ -71,7 +72,7 @@ void dl_print_backtrace_gdb() { name_buf[res] = 0; int child_pid = fork(); if (child_pid < 0) { - write (2, "Can't fork() to run gdb\n", 24); + std::ignore = write (2, "Can't fork() to run gdb\n", 24); _exit (0); } if (!child_pid) { @@ -83,7 +84,7 @@ void dl_print_backtrace_gdb() { waitpid (child_pid, nullptr, 0); } } else { - write (2, "can't get name of executable file to pass to gdb\n", 49); + std::ignore = write (2, "can't get name of executable file to pass to gdb\n", 49); } } diff --git a/compiler/compiler-settings.cpp b/compiler/compiler-settings.cpp index d19da1e18d..abd519d677 100644 --- a/compiler/compiler-settings.cpp +++ b/compiler/compiler-settings.cpp @@ -312,7 +312,7 @@ void CompilerSettings::init() { ss << " -std=c++17"; #elif __cplusplus <= 202002L ss << " -std=c++20"; - ss << " -Wno-unused-result -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; + ss << " -Wno-type-limits -Wno-attributes -Wno-ignored-attributes"; #else #error unsupported __cplusplus value #endif From 4f6d31102c2c7aa841413193802d205fff4c9e7d Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Thu, 18 Jul 2024 20:26:10 +0300 Subject: [PATCH 44/56] Add resetting the session status in session_close(), add check on NULL in getenv() --- runtime/sessions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 510a6683e0..688e59fc29 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -60,7 +60,7 @@ constexpr static auto C_HTTPONLY = "cookie_httponly"; // TO-DO: reconsider it const auto skeys = vk::to_array>({ {S_READ_CLOSE, false}, - {S_DIR, string(getenv("TMPDIR")).append("sessions/")}, + {S_DIR, string((getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp/").append("sessions/")}, {S_NAME, string("PHPSESSID")}, {S_LIFETIME, 1440}, {S_PROBABILITY, 1}, @@ -252,6 +252,7 @@ static void session_close() { fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); close_safe(get_sparam(S_FD).to_int()); } + set_sparam(S_STATUS, false); reset_sparams(); } From c08969a530802a227fc363533f24195175bb73e4 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Sat, 20 Jul 2024 19:10:48 +0300 Subject: [PATCH 45/56] Fix session_gc(), change mode of session files - add the resetting logic of fd before deleting files from dir, - change mode of session files from 0777 to 0666, - add new tag to filter session files from other files in session_gc(). --- runtime/sessions.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 688e59fc29..4655dd32ca 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -204,7 +204,7 @@ static bool session_open() { bool is_new = (!f$file_exists(get_sparam(S_PATH).to_string())) ? 1 : 0; // the interprocessor lock does not work - set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR | O_CREAT, 0777)); + set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR | O_CREAT, 0666)); if (get_sparam(S_FD).to_int() < 0) { php_warning("Failed to open the file %s", get_sparam(S_PATH).to_string().c_str()); @@ -230,6 +230,9 @@ static bool session_open() { int ret_gc_lifetime = get_tag(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, NULL, 0); if (is_new or ret_ctime < 0) { // add the creation data to metadata of file + int is_session = 1; // to filter sessions from other files in session_gc() + set_tag(get_sparam(S_PATH).to_string().c_str(), "is_session", &is_session, sizeof(int)); + int ctime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); set_tag(get_sparam(S_PATH).to_string().c_str(), S_CTIME, &ctime, sizeof(int)); } @@ -297,7 +300,7 @@ static bool session_write() { lock.l_pid = getpid(); fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); close_safe(get_sparam(S_FD).to_int()); - set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR, 0777)); + set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR, 0666)); lock.l_type = F_WRLCK; fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); @@ -377,6 +380,9 @@ static int session_gc(const bool &immediate = false) { return -1; } + // reset the fd before changing the session directory + close_safe(get_sparam(S_FD).to_int()); + struct flock lock; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; @@ -387,16 +393,23 @@ static int session_gc(const bool &immediate = false) { int result = 0; for (auto s = s_list.as_array().begin(); s != s_list.as_array().end(); ++s) { string path = s.get_value().to_string(); - if (path == string(".") or path == string("..")) { + if (path[0] == '.') { continue; } path = string(get_sparam(S_DIR).to_string()).append(path); if (path == get_sparam(S_PATH).to_string()) { continue; } + + { // filter session files from others + int is_session, ret_is_session = get_tag(path.c_str(), "is_session", &is_session, sizeof(int)); + if (ret_is_session < 0) { + continue; + } + } int fd; - if ((fd = open(path.c_str(), O_RDWR, 0777)) < 0) { + if ((fd = open_safe(path.c_str(), O_RDWR, 0666)) < 0) { php_warning("Failed to open file on path: %s", path.c_str()); continue; } @@ -410,6 +423,17 @@ static int session_gc(const bool &immediate = false) { ++result; } } + + lock.l_type = F_WRLCK; + lock.l_pid = getpid(); + set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR, 0666)); + if (get_sparam(S_FD).to_int() < 0) { + php_warning("Failed to reopen the file %s after session_gc()", get_sparam(S_PATH).to_string().c_str()); + session_abort(); + } else { + fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + } + return result; } From 6dc52416b44a97d8db903cfa83ce8687db7ad0cb Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Tue, 23 Jul 2024 22:00:15 +0300 Subject: [PATCH 46/56] Replace fcntl() logic with lockf() for blocking workers --- runtime/sessions.cpp | 59 +++++++++----------------------------------- 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 4655dd32ca..27f190a79b 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -192,7 +192,7 @@ static bool session_decode(const string &data) { } static bool session_open() { - if (get_sparam(S_FD).to_bool() && (fcntl(get_sparam(S_FD).to_int(), F_GETFD) != -1 || errno != EBADF)) { + if (get_sparam(S_FD).to_bool()) { return true; } @@ -203,7 +203,6 @@ static bool session_open() { set_sparam(S_PATH, string(get_sparam(S_DIR).to_string()).append(get_sparam(S_ID).to_string())); bool is_new = (!f$file_exists(get_sparam(S_PATH).to_string())) ? 1 : 0; - // the interprocessor lock does not work set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR | O_CREAT, 0666)); if (get_sparam(S_FD).to_int() < 0) { @@ -211,25 +210,12 @@ static bool session_open() { return false; } - struct flock lock; - lock.l_type = F_WRLCK; // Exclusive write lock - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - lock.l_pid = getpid(); - - int ret = fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); - - if (ret < 0 && errno == EDEADLK) { - php_warning("Attempt to lock alredy locked session file, path: %s", get_sparam(S_PATH).to_string().c_str()); - return false; - } + lockf(get_sparam(S_FD).to_int(), F_LOCK, 0); // set new metadata to the file int ret_ctime = get_tag(get_sparam(S_PATH).to_string().c_str(), S_CTIME, NULL, 0); int ret_gc_lifetime = get_tag(get_sparam(S_PATH).to_string().c_str(), S_LIFETIME, NULL, 0); - if (is_new or ret_ctime < 0) { - // add the creation data to metadata of file + if (is_new or ret_ctime < 0) { // add the creation data to metadata of file int is_session = 1; // to filter sessions from other files in session_gc() set_tag(get_sparam(S_PATH).to_string().c_str(), "is_session", &is_session, sizeof(int)); @@ -245,14 +231,8 @@ static bool session_open() { } static void session_close() { - if (get_sparam(S_FD).to_bool() && (fcntl(get_sparam(S_FD).to_int(), F_GETFD) != -1 || errno != EBADF)) { - struct flock lock; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - lock.l_pid = getpid(); - fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + if (get_sparam(S_FD).to_bool()) { + lockf(get_sparam(S_FD).to_int(), F_ULOCK, 0); close_safe(get_sparam(S_FD).to_int()); } set_sparam(S_STATUS, false); @@ -291,18 +271,8 @@ static bool session_read() { } static bool session_write() { - // rewind the S_FD of the session file - struct flock lock; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - lock.l_pid = getpid(); - fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); - close_safe(get_sparam(S_FD).to_int()); - set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR, 0666)); - lock.l_type = F_WRLCK; - fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + // rewind the fd of the session file + lseek(get_sparam(S_FD).to_int(), 0, SEEK_SET); string data = f$serialize(PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array()); ssize_t n = write_safe(get_sparam(S_FD).to_int(), data.c_str(), data.size(), get_sparam(S_PATH).to_string()); @@ -383,13 +353,6 @@ static int session_gc(const bool &immediate = false) { // reset the fd before changing the session directory close_safe(get_sparam(S_FD).to_int()); - struct flock lock; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - lock.l_pid = getpid(); - int result = 0; for (auto s = s_list.as_array().begin(); s != s_list.as_array().end(); ++s) { string path = s.get_value().to_string(); @@ -414,24 +377,24 @@ static int session_gc(const bool &immediate = false) { continue; } - if (fcntl(fd, F_SETLK, &lock) < 0) { + if (lockf(fd, F_TEST, 0) < 0) { + close_safe(fd); continue; } + close_safe(fd); if (session_expired(path)) { f$unlink(path); ++result; } } - lock.l_type = F_WRLCK; - lock.l_pid = getpid(); set_sparam(S_FD, open_safe(get_sparam(S_PATH).to_string().c_str(), O_RDWR, 0666)); if (get_sparam(S_FD).to_int() < 0) { php_warning("Failed to reopen the file %s after session_gc()", get_sparam(S_PATH).to_string().c_str()); session_abort(); } else { - fcntl(get_sparam(S_FD).to_int(), F_SETLKW, &lock); + lockf(get_sparam(S_FD).to_int(), F_LOCK, 0); } return result; From 8d4ad557709e604920f1d4c51accb2da65c54e1f Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 02:21:31 +0300 Subject: [PATCH 47/56] Add SameSite cookie option, implement new setcookie function with array arg --- runtime/interface.cpp | 38 +++++++++++++++++++++++++++++++++++++- runtime/interface.h | 2 ++ runtime/sessions.cpp | 25 +++++++++++++++++-------- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/runtime/interface.cpp b/runtime/interface.cpp index fc2537cee2..6568d7b605 100644 --- a/runtime/interface.cpp +++ b/runtime/interface.cpp @@ -372,7 +372,7 @@ void f$send_http_103_early_hints(const array & headers) { http_send_immediate_response(header.c_str(), header.size(), "\r\n", 2); } -void f$setrawcookie(const string &name, const string &value, int64_t expire, const string &path, const string &domain, bool secure, bool http_only) { +void setrawcookie_impl(const string &name, const string &value, int64_t expire, const string &path, const string &domain, bool secure, bool http_only, const string &samesite) { string date = f$gmdate(HTTP_DATE, expire); kphp_runtime_context.static_SB_spare.clean() << "Set-Cookie: " << name << '='; @@ -397,9 +397,45 @@ void f$setrawcookie(const string &name, const string &value, int64_t expire, con if (http_only) { kphp_runtime_context.static_SB_spare << "; HttpOnly"; } + if (!samesite.empty()) { + kphp_runtime_context.static_SB_spare << "; SameSite=" << samesite; + } header(kphp_runtime_context.static_SB_spare.c_str(), (int)kphp_runtime_context.static_SB_spare.size(), false); } +void setrawcookie_array(const string &name, const string &value, const array &options) { + int64_t expire = 0; + string path = string(); + string domain = string(); + string samesite = string(); + bool secure = false, http_only = false; + + for (auto it = options.begin(); it != options.end(); ++it) { + string key = it.get_key().to_string(); + if (key == string("expires")) { + expire = it.get_value().to_int(); + } else if (key == string("path")) { + path = it.get_value().to_string(); + } else if (key == string("domain")) { + domain = it.get_value().to_string(); + } else if (key == string("samesite")) { + samesite = it.get_value().to_string(); + } else if (key == string("secure")) { + secure = it.get_value().to_bool(); + } else if (key == string("httponly")) { + http_only = it.get_value().to_bool(); + } else { + php_warning("setcookie(): option \"%s\" is invalid", it.get_key().to_string().c_str()); + return; + } + } + setrawcookie_impl(name, value, expire, path, domain, secure, http_only, samesite); +} + +void f$setrawcookie(const string &name, const string &value, int64_t expire, const string &path, const string &domain, bool secure, bool http_only) { + setrawcookie_impl(name, value, expire, path, domain, secure, http_only, string("")); +} + void f$setcookie(const string &name, const string &value, int64_t expire, const string &path, const string &domain, bool secure, bool http_only) { f$setrawcookie(name, f$urlencode(value), expire, path, domain, secure, http_only); } diff --git a/runtime/interface.h b/runtime/interface.h index b1a05f8e55..51b9d3b811 100644 --- a/runtime/interface.h +++ b/runtime/interface.h @@ -56,6 +56,8 @@ void f$setcookie(const string &name, const string &value, int64_t expire = 0, co void f$setrawcookie(const string &name, const string &value, int64_t expire = 0, const string &path = string(), const string &domain = string(), bool secure = false, bool http_only = false); +void setrawcookie_array(const string &name, const string &value, const array &options = array()); + int64_t f$ignore_user_abort(Optional enable = Optional()); enum class ShutdownType { diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 27f190a79b..7e9d0dac6b 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -56,6 +56,7 @@ constexpr static auto C_LIFETIME = "cookie_lifetime"; constexpr static auto C_DOMAIN = "cookie_domain"; constexpr static auto C_SECURE = "cookie_secure"; constexpr static auto C_HTTPONLY = "cookie_httponly"; +constexpr static auto C_SAMESITE = "cookie_samesite"; // TO-DO: reconsider it const auto skeys = vk::to_array>({ @@ -69,7 +70,8 @@ const auto skeys = vk::to_array>({ {C_LIFETIME, 0}, {C_DOMAIN, string("")}, {C_SECURE, false}, - {C_HTTPONLY, false} + {C_HTTPONLY, false}, + {C_SAMESITE, string("")} }); static int set_tag(const char *path, const char *name, void *value, const size_t size) { @@ -107,12 +109,14 @@ static array session_get_cookie_params() { result.emplace_value(string(C_DOMAIN), skeys[8].second); result.emplace_value(string(C_SECURE), skeys[9].second); result.emplace_value(string(C_HTTPONLY), skeys[10].second); + result.emplace_value(string(C_SAMESITE), skeys[11].second); } else { result.emplace_value(string(C_PATH), get_sparam(C_PATH)); result.emplace_value(string(C_LIFETIME), get_sparam(C_LIFETIME)); result.emplace_value(string(C_DOMAIN), get_sparam(C_DOMAIN)); result.emplace_value(string(C_SECURE), get_sparam(C_SECURE)); result.emplace_value(string(C_HTTPONLY), get_sparam(C_HTTPONLY)); + result.emplace_value(string(C_SAMESITE), get_sparam(C_SAMESITE)); } return result; } @@ -297,14 +301,19 @@ static bool session_send_cookie() { if (expire > 0) { expire += std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); } - string domain = get_sparam(C_DOMAIN).to_string(); - bool secure = get_sparam(C_SECURE).to_bool(); - bool httponly = get_sparam(C_HTTPONLY).to_bool(); - string sid = f$urlencode(get_sparam(S_ID).to_string()); - string path = get_sparam(C_PATH).to_string(); + + array cookie_options; + cookie_options.emplace_value(string("expires"), expire); + cookie_options.emplace_value(string("path"), get_sparam(C_PATH).to_string()); + cookie_options.emplace_value(string("domain"), get_sparam(C_DOMAIN).to_string()); + cookie_options.emplace_value(string("secure"), get_sparam(C_SECURE).to_bool()); + cookie_options.emplace_value(string("httponly"), get_sparam(C_HTTPONLY).to_bool()); + cookie_options.emplace_value(string("samesite"), get_sparam(S_NAME).to_string()); + string name = get_sparam(S_NAME).to_string(); + string sid = f$urlencode(get_sparam(S_ID).to_string()); - f$setcookie(name, sid, expire, path, domain, secure, httponly); + setrawcookie_array(name, sid, cookie_options); return true; } @@ -440,7 +449,7 @@ static bool session_start() { if (php_globals.get_superglobals().v$_COOKIE.as_array().isset(get_sparam(S_NAME).to_string())) { id = php_globals.get_superglobals().v$_COOKIE.as_array().get_value(get_sparam(S_NAME).to_string()).to_string(); } - + if (id.to_bool() && !id.to_string().empty()) { if (!strpbrk(id.to_string().c_str(), "\r\n\t <>'\"\\")) { if (f$file_exists(string(get_sparam(S_DIR).to_string()).append(id.to_string()))) { From c17cda3f54828e473f10ef47a3bbe572b11ca44f Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 17:30:52 +0300 Subject: [PATCH 48/56] Add session.use_strict_mode option --- runtime/sessions.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 7e9d0dac6b..47239fe2a8 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -51,6 +51,7 @@ constexpr static auto S_LIFETIME = "gc_maxlifetime"; constexpr static auto S_PROBABILITY = "gc_probability"; constexpr static auto S_DIVISOR = "gc_divisor"; constexpr static auto S_SEND_COOKIE = "send_cookie"; +constexpr static auto S_STRICT_MODE = "use_strict_mode"; constexpr static auto C_PATH = "cookie_path"; constexpr static auto C_LIFETIME = "cookie_lifetime"; constexpr static auto C_DOMAIN = "cookie_domain"; @@ -66,6 +67,7 @@ const auto skeys = vk::to_array>({ {S_LIFETIME, 1440}, {S_PROBABILITY, 1}, {S_DIVISOR, 100}, + {S_STRICT_MODE, false}, {C_PATH, string("/")}, {C_LIFETIME, 0}, {C_DOMAIN, string("")}, @@ -104,12 +106,12 @@ static array session_get_cookie_params() { array result; if (PhpScriptMutableGlobals::current().get_superglobals().v$_KPHPSESSARR.as_array().empty()) { php_warning("Session cookie params cannot be received when there is no active session. Returned the default params"); - result.emplace_value(string(C_PATH), skeys[6].second); - result.emplace_value(string(C_LIFETIME), skeys[7].second); - result.emplace_value(string(C_DOMAIN), skeys[8].second); - result.emplace_value(string(C_SECURE), skeys[9].second); - result.emplace_value(string(C_HTTPONLY), skeys[10].second); - result.emplace_value(string(C_SAMESITE), skeys[11].second); + result.emplace_value(string(C_PATH), skeys[7].second); + result.emplace_value(string(C_LIFETIME), skeys[8].second); + result.emplace_value(string(C_DOMAIN), skeys[9].second); + result.emplace_value(string(C_SECURE), skeys[10].second); + result.emplace_value(string(C_HTTPONLY), skeys[11].second); + result.emplace_value(string(C_SAMESITE), skeys[12].second); } else { result.emplace_value(string(C_PATH), get_sparam(C_PATH)); result.emplace_value(string(C_LIFETIME), get_sparam(C_LIFETIME)); @@ -412,7 +414,8 @@ static int session_gc(const bool &immediate = false) { static bool session_initialize() { set_sparam(S_STATUS, true); - if (!get_sparam(S_ID).to_bool()) { + if (!get_sparam(S_ID).to_bool() + || (get_sparam(S_STRICT_MODE).to_bool() && !session_valid_id(get_sparam(S_ID).to_string()))) { if (!session_generate_id()) { php_warning( "Failed to create session ID: %s (path: %s)", @@ -425,7 +428,7 @@ static bool session_initialize() { set_sparam(S_SEND_COOKIE, true); } - if (!session_open() or !session_reset_id() or !session_read()) { + if (!session_reset_id() || !session_open() || !session_read()) { session_abort(); return false; } @@ -443,22 +446,16 @@ static bool session_start() { set_sparam(S_SEND_COOKIE, true); - if (!get_sparam(S_ID).to_bool()) { + if (!get_sparam(S_ID).to_bool()) { // Check session id in cookie values mixed id = false; PhpScriptMutableGlobals &php_globals = PhpScriptMutableGlobals::current(); if (php_globals.get_superglobals().v$_COOKIE.as_array().isset(get_sparam(S_NAME).to_string())) { id = php_globals.get_superglobals().v$_COOKIE.as_array().get_value(get_sparam(S_NAME).to_string()).to_string(); + set_sparam(S_ID, id.to_string()); } - - if (id.to_bool() && !id.to_string().empty()) { - if (!strpbrk(id.to_string().c_str(), "\r\n\t <>'\"\\")) { - if (f$file_exists(string(get_sparam(S_DIR).to_string()).append(id.to_string()))) { - set_sparam(S_SEND_COOKIE, false); - set_sparam(S_ID, id.to_string()); - } - } - } - } else if (strpbrk(get_sparam(S_ID).to_string().c_str(), "\r\n\t <>'\"\\")) { + } + + if (get_sparam(S_ID).to_bool() && (get_sparam(S_ID).to_string().empty() || strpbrk(get_sparam(S_ID).to_string().c_str(), "\r\n\t <>'\"\\"))) { set_sparam(S_ID, false); } From 14075516f3bd03e2701d275bb285dc8be1da858e Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 17:43:16 +0300 Subject: [PATCH 49/56] Add session_destroy() function --- runtime/sessions.cpp | 17 ++++++++--------- runtime/sessions.h | 4 +--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 47239fe2a8..702aefe18f 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -556,12 +556,11 @@ Optional f$session_id(const Optional &id) { return (prev_id.is_bool()) ? Optional{false} : Optional(prev_id.as_string()); } -// TO-DO -// bool f$session_destroy() { -// if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { -// php_warning("Trying to destroy uninitialized session"); -// return false; -// } -// sessions::session_close(); -// return true; -// } +bool f$session_destroy() { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Trying to destroy uninitialized session"); + return false; + } + sessions::session_close(); + return true; +} diff --git a/runtime/sessions.h b/runtime/sessions.h index ff5aa0b56e..a469745c66 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -12,6 +12,4 @@ Optional f$session_encode(); bool f$session_decode(const string &data); array f$session_get_cookie_params(); Optional f$session_id(const Optional &id = Optional()); - -// TO-DO -// bool f$session_destroy(); \ No newline at end of file +bool f$session_destroy(); \ No newline at end of file From 37ff87d1cf540670b436116215ddc7a615708e2f Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 19:23:15 +0300 Subject: [PATCH 50/56] Add session.sid_length option, add a check to mkdir() in session_open() --- runtime/sessions.cpp | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index 702aefe18f..b85a7987b9 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -12,6 +12,7 @@ #include "common/wrappers/to_array.h" #include "runtime/url.h" #include "runtime/math_functions.h" +#include "runtime/string_functions.h" namespace sessions { @@ -52,6 +53,7 @@ constexpr static auto S_PROBABILITY = "gc_probability"; constexpr static auto S_DIVISOR = "gc_divisor"; constexpr static auto S_SEND_COOKIE = "send_cookie"; constexpr static auto S_STRICT_MODE = "use_strict_mode"; +constexpr static auto S_ID_LENGTH = "sid_length"; constexpr static auto C_PATH = "cookie_path"; constexpr static auto C_LIFETIME = "cookie_lifetime"; constexpr static auto C_DOMAIN = "cookie_domain"; @@ -59,6 +61,8 @@ constexpr static auto C_SECURE = "cookie_secure"; constexpr static auto C_HTTPONLY = "cookie_httponly"; constexpr static auto C_SAMESITE = "cookie_samesite"; +constexpr static auto MAX_SID_LENGTH = 256; + // TO-DO: reconsider it const auto skeys = vk::to_array>({ {S_READ_CLOSE, false}, @@ -68,6 +72,7 @@ const auto skeys = vk::to_array>({ {S_PROBABILITY, 1}, {S_DIVISOR, 100}, {S_STRICT_MODE, false}, + {S_ID_LENGTH, 32}, {C_PATH, string("/")}, {C_LIFETIME, 0}, {C_DOMAIN, string("")}, @@ -100,18 +105,23 @@ static void initialize_sparams(const array &options) noexcept { } set_sparam(it.first, mixed(it.second)); } + + if (get_sparam(S_ID_LENGTH).to_int() < 22 || get_sparam(S_ID_LENGTH).to_int() > MAX_SID_LENGTH) { + set_sparam(S_ID_LENGTH, 32); + php_warning("session.configuration \"session.sid_length\" must be between 22 and 256. The default value is set"); + } } static array session_get_cookie_params() { array result; if (PhpScriptMutableGlobals::current().get_superglobals().v$_KPHPSESSARR.as_array().empty()) { php_warning("Session cookie params cannot be received when there is no active session. Returned the default params"); - result.emplace_value(string(C_PATH), skeys[7].second); - result.emplace_value(string(C_LIFETIME), skeys[8].second); - result.emplace_value(string(C_DOMAIN), skeys[9].second); - result.emplace_value(string(C_SECURE), skeys[10].second); - result.emplace_value(string(C_HTTPONLY), skeys[11].second); - result.emplace_value(string(C_SAMESITE), skeys[12].second); + result.emplace_value(string(C_PATH), skeys[8].second); + result.emplace_value(string(C_LIFETIME), skeys[9].second); + result.emplace_value(string(C_DOMAIN), skeys[10].second); + result.emplace_value(string(C_SECURE), skeys[11].second); + result.emplace_value(string(C_HTTPONLY), skeys[12].second); + result.emplace_value(string(C_SAMESITE), skeys[13].second); } else { result.emplace_value(string(C_PATH), get_sparam(C_PATH)); result.emplace_value(string(C_LIFETIME), get_sparam(C_LIFETIME)); @@ -153,7 +163,7 @@ static bool session_valid_id(const string &id) { } bool result = true; - for (auto i = (string("sess_").size()); i < id.size(); ++i) { + for (auto i = 0; i < id.size(); ++i) { if (!((id[i] >= 'a' && id[i] <= 'z') || (id[i] >= 'A' && id[i] <= 'Z') || (id[i] >= '0' && id[i] <= '9') @@ -163,16 +173,21 @@ static bool session_valid_id(const string &id) { break; } } + return result; } static bool session_generate_id() { - string id = f$uniqid(string("sess_")); - if (!session_valid_id(id)) { + Optional id = f$random_bytes(get_sparam(S_ID_LENGTH).to_int() / 2); + for (uint i = 0; i < 3 && (id.is_false() || !session_valid_id(f$bin2hex(id.val()))); ++i) { + id = f$random_bytes(get_sparam(S_ID_LENGTH).to_int() / 2); + } + + if (id.is_false() || !session_valid_id(f$bin2hex(id.val()))) { php_warning("Failed to create new ID\n"); return false; } - set_sparam(S_ID, id); + set_sparam(S_ID, f$bin2hex(id.val())); return true; } @@ -202,8 +217,9 @@ static bool session_open() { return true; } - if (!f$file_exists(get_sparam(S_DIR).to_string())) { - f$mkdir(get_sparam(S_DIR).to_string()); + if (!f$file_exists(get_sparam(S_DIR).to_string()) && !f$mkdir(get_sparam(S_DIR).to_string())) { + php_warning("Failed to create session directory on path %s", get_sparam(S_DIR).to_string().c_str()); + return false; } set_sparam(S_PATH, string(get_sparam(S_DIR).to_string()).append(get_sparam(S_ID).to_string())); @@ -428,7 +444,7 @@ static bool session_initialize() { set_sparam(S_SEND_COOKIE, true); } - if (!session_reset_id() || !session_open() || !session_read()) { + if (!session_open() || !session_reset_id() || !session_read()) { session_abort(); return false; } From 007e55b82cbfe7eabb1ac00783bf323f6e74b13f Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 19:56:55 +0300 Subject: [PATCH 51/56] Add session.lazy_write option --- runtime/sessions.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index b85a7987b9..cf0bc9b60b 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -54,6 +54,8 @@ constexpr static auto S_DIVISOR = "gc_divisor"; constexpr static auto S_SEND_COOKIE = "send_cookie"; constexpr static auto S_STRICT_MODE = "use_strict_mode"; constexpr static auto S_ID_LENGTH = "sid_length"; +constexpr static auto S_LAZY_WRITE = "lazy_write"; +constexpr static auto S_VARS = "session_buffered_variables"; constexpr static auto C_PATH = "cookie_path"; constexpr static auto C_LIFETIME = "cookie_lifetime"; constexpr static auto C_DOMAIN = "cookie_domain"; @@ -73,6 +75,7 @@ const auto skeys = vk::to_array>({ {S_DIVISOR, 100}, {S_STRICT_MODE, false}, {S_ID_LENGTH, 32}, + {S_LAZY_WRITE, true}, {C_PATH, string("/")}, {C_LIFETIME, 0}, {C_DOMAIN, string("")}, @@ -116,12 +119,12 @@ static array session_get_cookie_params() { array result; if (PhpScriptMutableGlobals::current().get_superglobals().v$_KPHPSESSARR.as_array().empty()) { php_warning("Session cookie params cannot be received when there is no active session. Returned the default params"); - result.emplace_value(string(C_PATH), skeys[8].second); - result.emplace_value(string(C_LIFETIME), skeys[9].second); - result.emplace_value(string(C_DOMAIN), skeys[10].second); - result.emplace_value(string(C_SECURE), skeys[11].second); - result.emplace_value(string(C_HTTPONLY), skeys[12].second); - result.emplace_value(string(C_SAMESITE), skeys[13].second); + result.emplace_value(string(C_PATH), skeys[9].second); + result.emplace_value(string(C_LIFETIME), skeys[10].second); + result.emplace_value(string(C_DOMAIN), skeys[11].second); + result.emplace_value(string(C_SECURE), skeys[12].second); + result.emplace_value(string(C_HTTPONLY), skeys[13].second); + result.emplace_value(string(C_SAMESITE), skeys[14].second); } else { result.emplace_value(string(C_PATH), get_sparam(C_PATH)); result.emplace_value(string(C_LIFETIME), get_sparam(C_LIFETIME)); @@ -284,8 +287,13 @@ static bool session_read() { } return false; } + + string read_data(result, n); + if (get_sparam(S_LAZY_WRITE).to_bool()) { + set_sparam(S_VARS, read_data); + } - if (!session_decode(string(result, n))) { + if (!session_decode(read_data)) { php_warning("Failed to unzerialize the data"); return false; } @@ -297,6 +305,10 @@ static bool session_write() { lseek(get_sparam(S_FD).to_int(), 0, SEEK_SET); string data = f$serialize(PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array()); + if (get_sparam(S_LAZY_WRITE).to_bool() && get_sparam(S_VARS).to_string() == data) { + return true; + } + ssize_t n = write_safe(get_sparam(S_FD).to_int(), data.c_str(), data.size(), get_sparam(S_PATH).to_string()); if (n < data.size()) { if (n == -1) { From d813b1a64f0f841e070ff2e8723d696e34674537 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 21:12:14 +0300 Subject: [PATCH 52/56] Add session_reset(), session_save_path(), session_unset() --- builtin-functions/kphp-full/_functions.txt | 3 +++ runtime/sessions.cpp | 29 +++++++++++++++++++++- runtime/sessions.h | 5 +++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/builtin-functions/kphp-full/_functions.txt b/builtin-functions/kphp-full/_functions.txt index dc980d4ba4..bdc9043c33 100644 --- a/builtin-functions/kphp-full/_functions.txt +++ b/builtin-functions/kphp-full/_functions.txt @@ -786,6 +786,9 @@ function session_destroy() ::: bool; function session_encode() ::: string | false; function session_decode($data ::: string) ::: bool; function session_get_cookie_params() ::: array; +function session_reset() ::: bool; +function session_save_path($path ::: ?string = null) ::: string | false; +function session_unset() ::: bool; define('PHP_ROUND_HALF_UP', 123423141); define('PHP_ROUND_HALF_DOWN', 123423144); diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index cf0bc9b60b..d80bbd2b17 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -217,6 +217,7 @@ static bool session_decode(const string &data) { static bool session_open() { if (get_sparam(S_FD).to_bool()) { + lseek(get_sparam(S_FD).to_int(), 0, SEEK_SET); return true; } @@ -302,7 +303,7 @@ static bool session_read() { static bool session_write() { // rewind the fd of the session file - lseek(get_sparam(S_FD).to_int(), 0, SEEK_SET); + session_open(); string data = f$serialize(PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array()); if (get_sparam(S_LAZY_WRITE).to_bool() && get_sparam(S_VARS).to_string() == data) { @@ -592,3 +593,29 @@ bool f$session_destroy() { sessions::session_close(); return true; } + +bool f$session_reset() { + return (sessions::get_sparam(sessions::S_STATUS).to_bool() && sessions::session_initialize()); +} + +Optional f$session_save_path(const Optional &path) { + if (path.has_value() && sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Session save path cannot be changed when a session is active"); + return Optional{false}; + } + + Optional prev_path(sessions::get_sparam(sessions::S_DIR).to_string()); + if (path.has_value() && !path.val().to_string().empty()) { + sessions::set_sparam(sessions::S_DIR, path.val()); + } + return prev_path; +} + +bool f$session_unset() { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + return false; + } + + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array().clear(); + return true; +} diff --git a/runtime/sessions.h b/runtime/sessions.h index a469745c66..c715abb2d9 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -12,4 +12,7 @@ Optional f$session_encode(); bool f$session_decode(const string &data); array f$session_get_cookie_params(); Optional f$session_id(const Optional &id = Optional()); -bool f$session_destroy(); \ No newline at end of file +bool f$session_destroy(); +bool f$session_reset(); +Optional f$session_save_path(const Optional &path = Optional()); +bool f$session_unset(); \ No newline at end of file From be0f21a4c48cf7648f48b97a6c14c69f0d400376 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 22:56:49 +0300 Subject: [PATCH 53/56] Delete undue php file --- tests/phpt/sessions/01.php | 51 -------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 tests/phpt/sessions/01.php diff --git a/tests/phpt/sessions/01.php b/tests/phpt/sessions/01.php deleted file mode 100644 index da1a1d95b3..0000000000 --- a/tests/phpt/sessions/01.php +++ /dev/null @@ -1,51 +0,0 @@ -@ok -session_id = false; - } - - function handleRequest(): ?KphpJobWorkerResponse { - $response = new Response(); - $status = session_start(); - if ($status) { - - } - $response->session_id = - } -} - -class Response implements KphpJobWorkerResponse { - /** @var AI */ - public $ai = null; - - /** @var string|false */ - public $session_id = false; -} - - -$request1 = new Request(); -$request1->ai = new A1(); -$request2 = Request(); -$request2->ai = new A2(); -$ids = array(); -kphp_job_worker_start($request, -1); - - From 27aef61edf62d0e61f2ddeea03c9a66ff4a16ad8 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Wed, 24 Jul 2024 23:00:13 +0300 Subject: [PATCH 54/56] Hide session_destroy() --- builtin-functions/kphp-full/_functions.txt | 2 +- runtime/sessions.cpp | 20 +++++++++++--------- runtime/sessions.h | 6 ++++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/builtin-functions/kphp-full/_functions.txt b/builtin-functions/kphp-full/_functions.txt index bdc9043c33..61a2387cc8 100644 --- a/builtin-functions/kphp-full/_functions.txt +++ b/builtin-functions/kphp-full/_functions.txt @@ -782,13 +782,13 @@ function session_write_close() ::: bool; function session_gc() ::: bool; function session_status() ::: int; function session_id($id ::: ?string = null) ::: string | false; -function session_destroy() ::: bool; function session_encode() ::: string | false; function session_decode($data ::: string) ::: bool; function session_get_cookie_params() ::: array; function session_reset() ::: bool; function session_save_path($path ::: ?string = null) ::: string | false; function session_unset() ::: bool; +// function session_destroy() ::: bool; define('PHP_ROUND_HALF_UP', 123423141); define('PHP_ROUND_HALF_DOWN', 123423144); diff --git a/runtime/sessions.cpp b/runtime/sessions.cpp index d80bbd2b17..92d77d3c90 100644 --- a/runtime/sessions.cpp +++ b/runtime/sessions.cpp @@ -585,15 +585,6 @@ Optional f$session_id(const Optional &id) { return (prev_id.is_bool()) ? Optional{false} : Optional(prev_id.as_string()); } -bool f$session_destroy() { - if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { - php_warning("Trying to destroy uninitialized session"); - return false; - } - sessions::session_close(); - return true; -} - bool f$session_reset() { return (sessions::get_sparam(sessions::S_STATUS).to_bool() && sessions::session_initialize()); } @@ -619,3 +610,14 @@ bool f$session_unset() { PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array().clear(); return true; } + +/* TO-DO: +bool f$session_destroy() { + if (!sessions::get_sparam(sessions::S_STATUS).to_bool()) { + php_warning("Trying to destroy uninitialized session"); + return false; + } + sessions::session_close(); + return true; +} +*/ diff --git a/runtime/sessions.h b/runtime/sessions.h index c715abb2d9..6b8ffcf29b 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -12,7 +12,9 @@ Optional f$session_encode(); bool f$session_decode(const string &data); array f$session_get_cookie_params(); Optional f$session_id(const Optional &id = Optional()); -bool f$session_destroy(); bool f$session_reset(); Optional f$session_save_path(const Optional &path = Optional()); -bool f$session_unset(); \ No newline at end of file +bool f$session_unset(); + +// TO-DO: +// bool f$session_destroy(); \ No newline at end of file From e8333e942a6b6f17665018a700dbd1949a21fbfc Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Thu, 25 Jul 2024 01:43:14 +0300 Subject: [PATCH 55/56] Update cpp tests --- tests/cpp/runtime/sessions-test.cpp | 180 ++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 11 deletions(-) diff --git a/tests/cpp/runtime/sessions-test.cpp b/tests/cpp/runtime/sessions-test.cpp index 2354389912..2cf6145c8f 100644 --- a/tests/cpp/runtime/sessions-test.cpp +++ b/tests/cpp/runtime/sessions-test.cpp @@ -1,54 +1,212 @@ #include +#include #include "runtime/files.h" #include "runtime/sessions.h" +#include "runtime/php-script-globals.h" +#include "runtime/serialize-functions.h" +#include "runtime/exec.h" + +constexpr int SESSION_NONE = 1; +constexpr int SESSION_ACTIVE = 2; + +const auto tmpdir_path = string(getenv("TMPDIR") != nullptr ? getenv("TMPDIR") : "/tmp/"); +const auto session_dir_path = string(tmpdir_path).append("sessions/"); +const auto example_dir_path = string(tmpdir_path).append("example/"); TEST(sessions_test, test_session_id_with_invalid_id) { - const string dir_path = string(getenv("TMPDIR")).append("sessions/"); const string id = string("\t12345678\\\r"); ASSERT_FALSE(f$session_id(id).has_value()); ASSERT_TRUE(f$session_start()); ASSERT_NE(f$session_id().val(), id); - const string full_path = string(dir_path).append(f$session_id().val()); + const string full_path = string(session_dir_path).append(f$session_id().val()); ASSERT_TRUE(f$file_exists(full_path)); ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(session_dir_path)); } TEST(sessions_test, test_session_id_with_valid_id) { - const string dir_path = string(getenv("TMPDIR")).append("sessions/"); const string id = string("sess_668d4f818ca3b"); ASSERT_FALSE(f$session_id(id).has_value()); ASSERT_TRUE(f$session_start()); + ASSERT_TRUE(f$session_id().has_value() && !f$session_id().val().empty()); ASSERT_EQ(f$session_id().val(), id); - const string full_path = string(dir_path).append(id); + const string full_path = string(session_dir_path).append(id); ASSERT_TRUE(f$file_exists(full_path)); ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(session_dir_path)); } TEST(sessions_test, test_session_start) { ASSERT_TRUE(f$session_start()); ASSERT_FALSE(f$session_start()); ASSERT_TRUE(f$session_abort()); + ASSERT_TRUE(f$session_start()); + ASSERT_FALSE(f$session_start()); + f$exec(string("rm -rf ").append(session_dir_path)); } TEST(sessions_test, test_session_start_with_params) { array predefined_consts = array(); - const string dir_path = string(getenv("TMPDIR")).append("example/"); - predefined_consts.emplace_value(string("save_path"), dir_path); + + predefined_consts.emplace_value(string("save_path"), example_dir_path); ASSERT_TRUE(f$session_start(predefined_consts)); - ASSERT_TRUE(f$file_exists(string(dir_path).append(f$session_id().val()))); + ASSERT_TRUE(f$session_id().has_value() && !f$session_id().val().empty()); + ASSERT_TRUE(f$file_exists(string(example_dir_path).append(f$session_id().val()))); ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(example_dir_path)); } TEST(sessions_test, test_session_status) { - const int SESSION_NONE = 1; - const int SESSION_ACTIVE = 2; - ASSERT_EQ(f$session_status(), SESSION_NONE); ASSERT_TRUE(f$session_start()); ASSERT_EQ(f$session_status(), SESSION_ACTIVE); ASSERT_TRUE(f$session_abort()); ASSERT_EQ(f$session_status(), SESSION_NONE); -} \ No newline at end of file + + f$exec(string("rm -rf ").append(session_dir_path)); +} + +TEST(sessions_test, test_session_save_path) { + f$session_start(); + ASSERT_TRUE(f$session_save_path().has_value() && !f$session_save_path().val().empty()); + ASSERT_EQ(f$session_save_path().val(), session_dir_path); + f$session_abort(); + + array predefined_consts; + predefined_consts.emplace_value(string("save_path"), example_dir_path); + ASSERT_TRUE(f$session_start(predefined_consts)); + ASSERT_TRUE(f$session_save_path().has_value() && !f$session_save_path().val().empty()); + ASSERT_EQ(f$session_save_path().val(), example_dir_path); + f$session_abort(); + + f$exec(string("rm -rf ").append(session_dir_path)); + f$exec(string("rm -rf ").append(example_dir_path)); +} + +TEST(sessions_test, test_session_commit) { + f$session_start(); + const string id = f$session_id().val(); + const string file_path = string(session_dir_path).append(id); + + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array().emplace_value(string("message"), string("hello")); + ASSERT_TRUE(f$session_commit()); + + struct stat buf; + int fd = open_safe(file_path.c_str(), O_RDWR, 0666); + fstat(fd, &buf); + char result[buf.st_size]; + ssize_t n = read_safe(fd, result, buf.st_size, file_path); + string read_data(result, n); + close_safe(fd); + + array session_array; + session_array.emplace_value(string("message"), string("hello")); + string write_data = f$serialize(session_array); + + ASSERT_EQ(read_data, write_data); + + f$session_id(id); + f$session_start(); + ASSERT_TRUE(f$session_id().has_value() && !f$session_id().val().empty()); + ASSERT_EQ(f$session_id().val(), id); + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array().emplace_value(string("message"), string("hello")); + f$session_abort(); + ASSERT_FALSE(f$session_commit()); + + fd = open_safe(file_path.c_str(), O_RDWR, 0666); + fstat(fd, &buf); + n = read_safe(fd, result, buf.st_size, file_path); + read_data = string(result, n); + ASSERT_EQ(read_data, write_data); + + f$exec(string("rm -rf ").append(session_dir_path)); +} + +TEST(sessions_test, test_session_decode) { + f$session_start(); + array data; + data.emplace_value(string("first"), string("hello world")); + data.emplace_value(string("second"), 60); + data.emplace_value(3, string("smth")); + + string to_write = f$serialize(data); + ASSERT_TRUE(f$session_decode(to_write)); + + string result = f$serialize(PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array()); + ASSERT_EQ(to_write, result); + + to_write = f$serialize(array()); + ASSERT_TRUE(f$session_decode(to_write)); + result = f$serialize(PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array()); + ASSERT_EQ(result, to_write); + ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(session_dir_path)); +} + +TEST(sessions_test, test_session_encode) { + f$session_start(); + array data; + data.emplace_value(string("first"), string("hello world")); + data.emplace_value(string("second"), 60); + data.emplace_value(3, string("smth")); + + string to_read = f$serialize(data); + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION = data; + ASSERT_TRUE(f$session_encode().has_value() && !f$session_encode().val().empty()); + ASSERT_EQ(f$session_encode().val(), to_read); + ASSERT_TRUE(f$session_abort()); + + f$session_start(); + ASSERT_TRUE(f$session_encode().has_value() && !f$session_encode().val().empty()); + ASSERT_EQ(f$session_encode().val(), f$serialize(array())); + ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(session_dir_path)); +} + +TEST(sessions_test, test_session_reset) { + f$session_start(); + ASSERT_TRUE(f$session_id().has_value() && !f$session_id().val().empty()); + string id = f$session_id().val(); + array data; + data.emplace_value(string("first"), string("hello world")); + data.emplace_value(string("second"), 60); + data.emplace_value(3, string("smth")); + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION = data; + ASSERT_TRUE(f$session_commit()); + + f$session_id(id); + f$session_start(); + ASSERT_TRUE(f$session_id().has_value() && !f$session_id().val().empty()); + ASSERT_EQ(f$session_id().val(), id); + array new_data; + new_data.emplace_value(string("first"), string("buy")); + new_data.emplace_value(string("second"), 1000); + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION = new_data; + ASSERT_TRUE(f$session_reset()); + new_data = PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array(); + ASSERT_EQ(f$serialize(data), f$serialize(new_data)); + ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(session_dir_path)); +} + +TEST(sessions_test, test_session_unset) { + f$session_start(); + array data; + data.emplace_value(string("first"), string("hello world")); + PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION = data; + ASSERT_TRUE(f$session_unset()); + data = PhpScriptMutableGlobals::current().get_superglobals().v$_SESSION.as_array(); + ASSERT_EQ(f$serialize(data), f$serialize(array())); + ASSERT_TRUE(f$session_abort()); + + f$exec(string("rm -rf ").append(session_dir_path)); +} From 4efbde7d9a756648242a2adc4fedd76ece860cc8 Mon Sep 17 00:00:00 2001 From: Marat Omarov Date: Thu, 25 Jul 2024 02:46:30 +0300 Subject: [PATCH 56/56] Add to-do list --- runtime/sessions.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/runtime/sessions.h b/runtime/sessions.h index 6b8ffcf29b..91b5a91cf1 100644 --- a/runtime/sessions.h +++ b/runtime/sessions.h @@ -17,4 +17,9 @@ Optional f$session_save_path(const Optional &path = Optional