-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add casr-lua
#231
base: master
Are you sure you want to change the base?
Add casr-lua
#231
Changes from 14 commits
d4eeeea
68aba4c
0b1c712
8287fb0
0edebae
0d8c6e5
15de25f
186078b
d644b14
9542a37
e3e8c3a
7c7c7c2
94a0235
d4606fd
0171139
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
use casr::util; | ||
use libcasr::{ | ||
init_ignored_frames, | ||
lua::LuaException, | ||
report::CrashReport, | ||
severity::Severity, | ||
stacktrace::Filter, | ||
stacktrace::Stacktrace, | ||
stacktrace::{CrashLine, CrashLineExt}, | ||
}; | ||
|
||
use anyhow::{bail, Result}; | ||
use clap::{Arg, ArgAction, ArgGroup}; | ||
use std::path::{Path, PathBuf}; | ||
use std::process::Command; | ||
|
||
fn main() -> Result<()> { | ||
let matches = clap::Command::new("casr-lua") | ||
.version(clap::crate_version!()) | ||
.about("Create CASR reports (.casrep) from Lua reports") | ||
.term_width(90) | ||
.arg( | ||
Arg::new("output") | ||
.short('o') | ||
.long("output") | ||
.action(ArgAction::Set) | ||
.value_parser(clap::value_parser!(PathBuf)) | ||
.value_name("REPORT") | ||
.help( | ||
"Path to save report. Path can be a directory, then report name is generated", | ||
), | ||
) | ||
.arg( | ||
Arg::new("stdout") | ||
.action(ArgAction::SetTrue) | ||
.long("stdout") | ||
.help("Print CASR report to stdout"), | ||
) | ||
.group( | ||
ArgGroup::new("out") | ||
.args(["stdout", "output"]) | ||
.required(true), | ||
) | ||
.arg( | ||
Arg::new("stdin") | ||
.long("stdin") | ||
.action(ArgAction::Set) | ||
.value_parser(clap::value_parser!(PathBuf)) | ||
.value_name("FILE") | ||
.help("Stdin file for program"), | ||
) | ||
.arg( | ||
Arg::new("timeout") | ||
.short('t') | ||
.long("timeout") | ||
.action(ArgAction::Set) | ||
.default_value("0") | ||
.value_name("SECONDS") | ||
.help("Timeout (in seconds) for target execution, 0 value means that timeout is disabled") | ||
.value_parser(clap::value_parser!(u64)) | ||
) | ||
.arg( | ||
Arg::new("ignore") | ||
.long("ignore") | ||
.action(ArgAction::Set) | ||
.value_parser(clap::value_parser!(PathBuf)) | ||
.value_name("FILE") | ||
.help("File with regular expressions for functions and file paths that should be ignored"), | ||
) | ||
.arg( | ||
Arg::new("strip-path") | ||
.long("strip-path") | ||
.env("CASR_STRIP_PATH") | ||
.action(ArgAction::Set) | ||
.value_name("PREFIX") | ||
.help("Path prefix to strip from stacktrace"), | ||
) | ||
.arg( | ||
Arg::new("ARGS") | ||
.action(ArgAction::Set) | ||
.num_args(1..) | ||
.last(true) | ||
.required(true) | ||
.help("Add \"-- <path> <arguments>\" to run"), | ||
) | ||
.get_matches(); | ||
|
||
init_ignored_frames!("lua"); | ||
if let Some(path) = matches.get_one::<PathBuf>("ignore") { | ||
util::add_custom_ignored_frames(path)?; | ||
} | ||
// Get program args. | ||
let argv: Vec<&str> = if let Some(argvs) = matches.get_many::<String>("ARGS") { | ||
argvs.map(|s| s.as_str()).collect() | ||
} else { | ||
bail!("Wrong arguments for starting program"); | ||
}; | ||
|
||
// Get stdin for target program. | ||
let stdin_file = util::stdin_from_matches(&matches)?; | ||
|
||
// Get timeout | ||
let timeout = *matches.get_one::<u64>("timeout").unwrap(); | ||
|
||
// Run program. | ||
let mut cmd = Command::new(argv[0]); | ||
if let Some(ref file) = stdin_file { | ||
cmd.stdin(std::fs::File::open(file)?); | ||
} | ||
if argv.len() > 1 { | ||
cmd.args(&argv[1..]); | ||
} | ||
let result = util::get_output(&mut cmd, timeout, true)?; | ||
let stderr = String::from_utf8_lossy(&result.stderr); | ||
|
||
// Create report. | ||
let mut report = CrashReport::new(); | ||
report.executable_path = argv[0].to_string(); | ||
if argv.len() > 1 { | ||
if let Some(fname) = Path::new(argv[0]).file_name() { | ||
let fname = fname.to_string_lossy(); | ||
if fname.starts_with("lua") && !fname.ends_with(".lua") && argv[1].ends_with(".lua") { | ||
report.executable_path = argv[1].to_string(); | ||
} | ||
} | ||
} | ||
report.proc_cmdline = argv.join(" "); | ||
let _ = report.add_os_info(); | ||
let _ = report.add_proc_environ(); | ||
|
||
// Extract lua exception | ||
let Some(exception) = LuaException::new(&stderr) else { | ||
bail!("Lua exception is not found!"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lua code: #!/bin/env lua
local function f1()
error('error is triggered', 1)
end
local function f2()
f1()
end
local function f3()
f2()
end
local function f4()
f3()
end
local function f5()
f4()
end
local thread = coroutine.create(f5)
local executed_ok, message = coroutine.resume(thread)
if not executed_ok then
print("Error: "..message.." in ".. debug.traceback(thread))
end
Should it be supported? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm... I assumed there was always going to be something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait... That's just debug info in stdout, not error message (although it contains word There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second issue is multiple call of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To sum up the above, I think we should not to support it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stack trace for assertions does not work:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Idk, It works fine for me |
||
}; | ||
|
||
// Parse exception | ||
report.lua_report = exception.lua_report(); | ||
report.stacktrace = exception.extract_stacktrace()?; | ||
report.execution_class = exception.severity()?; | ||
if let Ok(crashline) = exception.crash_line() { | ||
report.crashline = crashline.to_string(); | ||
if let CrashLine::Source(debug) = crashline { | ||
if let Some(sources) = CrashReport::sources(&debug) { | ||
report.source = sources; | ||
} | ||
} | ||
} | ||
let stacktrace = exception.parse_stacktrace()?; | ||
if let Some(path) = matches.get_one::<String>("strip-path") { | ||
util::strip_paths(&mut report, &stacktrace, path); | ||
} | ||
|
||
//Output report | ||
util::output_report(&report, &matches, &argv) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#!/bin/env lua | ||
|
||
function f(a, b) | ||
a = a .. 'qwer' | ||
b = b * 123 | ||
c = a / b | ||
return c | ||
end | ||
|
||
function g(a) | ||
a = a .. 'qwer' | ||
b = 123 | ||
c = f(a, b) | ||
return c | ||
end | ||
|
||
function h() | ||
a = 'qwer' | ||
c = g(a) | ||
return c | ||
end | ||
|
||
print(h()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imagine a Lua code like the following:
that produces an output:
casr-lua
will not find traceback there:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error occurs only due to extra spaces after traceback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can think about storing custom (maybe multiline) error as
Explanation
orDescription
fields, but it's not clear how to extractShortDescription
or etcThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed