What's os.geteuid() do? - python-2.x

I was trying to debug a Python 2 script running on Raspbian (Raspberry Pi flavoured Debian Linux) which had code like
euid = os.geteuid()
if euid != 0:
print("you must be root!")
exit(1)
It seemed like, in the user's environment, euid would sometimes be nonzero even if the script was called with sudo.
To investigate whether this was actually the case, I tried to figure out what os.geteuid() is actually doing.
Since the os module is pretty OS-specific by its nature, the source doesn't actually have a clear definition for os.geteuid().
I also tried hg cloneing the source and compiling it, then using inspect.findsource(os.geteuid), but:
TypeError: <built-in function geteuid> is not a module, class, method, function, traceback, frame, or code object
It's... a builtin? Then "geteuid" in dir(__import__("__builtin__")) should be True, but it isn't.
Is geteuid's definition hidden because it could be spoofed into returning the wrong thing (and that would be bad)? Where can I see these sorts of functions' actual source?

ASCII stupid question, get a stupid ANSI.
I did try full-text searching the source, but apparently I used the wrong command the first time and gave up.
$ grep -rnw '.' -e "geteuid"
./Misc/setuid-prog.c:129: uid_t euid = geteuid();
./Lib/site.py:209: if hasattr(os, "getuid") and hasattr(os, "geteuid"):
./Lib/site.py:211: if os.geteuid() != os.getuid():
./Lib/test/test_shutil.py:84: #unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
./Lib/test/test_httpservers.py:339: if os.name == 'posix' and os.geteuid() != 0:
./Lib/test/test_httpservers.py:395:#unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
./Lib/test/test_spwd.py:8:#unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
./Lib/test/test_posix.py:44: "getegid", "geteuid", "getgid", "getgroups",
./Lib/test/test_argparse.py:1532:#unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
Binary file ./Lib/tarfile.py matches
./Lib/rexec.py:148: 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')
Binary file ./Modules/posixmodule.o matches
./Modules/posixmodule.c:4047:"geteuid() -> euid\n\n\
./Modules/posixmodule.c:4053: return _PyInt_FromUid(geteuid());
./Modules/posixmodule.c:8944: {"geteuid", posix_geteuid, METH_NOARGS, posix_geteuid__doc__},
./Doc/library/rexec.rst:234: 'times', 'uname', 'getpid', 'getppid', 'getcwd', 'getuid', 'getgid', 'geteuid',
./Doc/library/os.rst:136:.. function:: geteuid()
Binary file ./python matches
Binary file ./libpython2.7.a matches
./Modules/posixmodule.c:4053, indeed:
#ifdef HAVE_GETEUID
PyDoc_STRVAR(posix_geteuid__doc__,
"geteuid() -> euid\n\n\
Return the current process's effective user id.");
static PyObject *
posix_geteuid(PyObject *self, PyObject *noargs)
{
return _PyInt_FromUid(geteuid());
}
#endif
I don't know what I expected, subprocess.check_output(["id"])?
It uses the C standard library, it's never wrong.

Related

How to stop ImageMagick in Ruby (Rmagick) evaluating an # sign in text annotation

In an app I recently built for a client the following code resulted in the variable #nameText being evaluated, and then resulting in an error 'no text' (since the variable doesn't exist).
To get around this I used gsub, as per the example below. Is there a way to tell Magick not to evaluate the string at all?
require 'RMagick'
#image = Magick::Image.read( '/path/to/image.jpg' ).first
#nameText = '#SomeTwitterUser'
#text = Magick::Draw.new
#text.font_family = 'Futura'
#text.pointsize = 22
#text.font_weight = Magick::BoldWeight
# Causes error 'no text'...
# #text.annotate( #image, 0,0,200,54, #nameText )
#text.annotate( #image, 0,0,200,54, #nameText.gsub('#', '\#') )
This is the C code from RMagick that is returning the error:
// Translate & store in Draw structure
draw->info->text = InterpretImageProperties(NULL, image, StringValuePtr(text));
if (!draw->info->text)
{
rb_raise(rb_eArgError, "no text");
}
It is the call to InterpretImageProperties that is modifying the input text - but it is not Ruby, or a Ruby instance variable that it is trying to reference. The function is defined here in the Image Magick core library: http://www.imagemagick.org/api/MagickCore/property_8c_source.html#l02966
Look a bit further down, and you can see the code:
/* handle a '#' replace string from file */
if (*p == '#') {
p++;
if (*p != '-' && (IsPathAccessible(p) == MagickFalse) ) {
(void) ThrowMagickException(&image->exception,GetMagickModule(),
OptionError,"UnableToAccessPath","%s",p);
return((char *) NULL);
}
return(FileToString(p,~0,&image->exception));
}
In summary, this is a core library feature which will attempt to load text from file (named SomeTwitterUser in your case, I have confirmed this -try it!), and your work-around is probably the best you can do.
For efficiency, and minimal changes to input strings, you could rely on the selectivity of the library code and only modify the string if it starts with #:
#text.annotate( #image, 0,0,200,54, #name_string.gsub( /^#/, '\#') )

GCC plugin: 'internal compiler error' in passes.c

I have been writing a GCC inter procedural plugin where I have to insert GIMPLE statements
at certain points in the program. After this I perform a data flow analysis on the complete
program. When I am done with my analysis I am removing those newly inserted GIMPLE statements.
My analysis is getting completed but just before exiting from it the following message is generated:
internal compiler error: in execute_ipa_pass_list, at passes.c:1817
This is surely because of the insertion of GIMPLE statements, if I don't do that I won't get this error message.
Could anyone help me out and explain what is the problem and how to fix it?
This usually happens when GCC code contains an assertion which turns out to be false.
The line 1817 in passes.c (which is part of the GCC sources, in the gcc sub-directory of the GCC source tree) has a piece of code which looks like:
gcc_assert (some_condition);
In your case, some_condition was false, but the compiler expects it to be always true (this is why the author of the code wrote the assertion in the first place).
You did something in your plugin which made it false, and you need to fix it.
What did you do wrong? It really depends. Open up passes.c and find that line, and see what it is checking. In my copy of GCC, the relevant function reads:
void
execute_ipa_pass_list (struct opt_pass *pass)
{
do
{
/* An assertion. */
gcc_assert (!current_function_decl);
/* Another assertion. */
gcc_assert (!cfun);
/* Another assertion. */
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (execute_one_pass (pass) && pass->sub)
{
if (pass->sub->type == GIMPLE_PASS)
{
invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
do_per_function_toporder ((void (*)(void *))execute_pass_list,
pass->sub);
invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
}
else if (pass->sub->type == SIMPLE_IPA_PASS
|| pass->sub->type == IPA_PASS)
execute_ipa_pass_list (pass->sub);
else
gcc_unreachable ();
}
/* Another assertion. */
gcc_assert (!current_function_decl);
cgraph_process_new_functions ();
pass = pass->next;
}
while (pass);
}
There are four gcc_assert statements. Your plugin caused one of them to become false. i.e. you messed with one of the variables:
current_function_decl
cfun
pass->type
This is probably what's wrong.

Forcing a package's function to use user-provided function

I'm running into a problem with the MNP package which I've traced to an unfortunate call to deparse (whose maximum width is limited to 500 characters).
Background (easily skippable if you're bored)
Because mnp uses a somewhat idiosyncratic syntax to allow for varying choice sets (you include cbind(choiceA,choiceB,...) in the formula definition), the left hand side of my formula call is 1700 characters or so when model.matrix.default calls deparse on it. Since deparse supports a maximum width.cutoff of 500 characters, the sapply(attr(t, "variables"), deparse, width.cutoff = 500)[-1L] line in model.matrix.default has as its first element:
[1] "cbind(plan1, plan2, plan3, plan4, plan5, plan6, plan7, plan8, plan9, plan10, plan11, plan12, plan13, plan14, plan15, plan16, plan17, plan18, plan19, plan20, plan21, plan22, plan23, plan24, plan25, plan26, plan27, plan28, plan29, plan30, plan31, plan32, plan33, plan34, plan35, plan36, plan37, plan38, plan39, plan40, plan41, plan42, plan43, plan44, plan45, plan46, plan47, plan48, plan49, plan50, plan51, plan52, plan53, plan54, plan55, plan56, plan57, plan58, plan59, plan60, plan61, plan62, plan63, "
[2] " plan64, plan65, plan66, plan67, plan68, plan69, plan70, plan71, plan72, plan73, plan74, plan75, plan76, plan77, plan78, plan79, plan80, plan81, plan82, plan83, plan84, plan85, plan86, plan87, plan88, plan89, plan90, plan91, plan92, plan93, plan94, plan95, plan96, plan97, plan98, plan99, plan100, plan101, plan102, plan103, plan104, plan105, plan106, plan107, plan108, plan109, plan110, plan111, plan112, plan113, plan114, plan115, plan116, plan117, plan118, plan119, plan120, plan121, plan122, plan123, "
[3] " plan124, plan125, plan126, plan127, plan128, plan129, plan130, plan131, plan132, plan133, plan134, plan135, plan136, plan137, plan138, plan139, plan140, plan141, plan142, plan143, plan144, plan145, plan146, plan147, plan148, plan149, plan150, plan151, plan152, plan153, plan154, plan155, plan156, plan157, plan158, plan159, plan160, plan161, plan162, plan163, plan164, plan165, plan166, plan167, plan168, plan169, plan170, plan171, plan172, plan173, plan174, plan175, plan176, plan177, plan178, plan179, "
[4] " plan180, plan181, plan182, plan183, plan184, plan185, plan186, plan187, plan188, plan189, plan190, plan191, plan192, plan193, plan194, plan195, plan196, plan197, plan198, plan199, plan200, plan201, plan202, plan203, plan204, plan205, plan206, plan207, plan208, plan209, plan210, plan211, plan212, plan213, plan214, plan215, plan216, plan217, plan218, plan219, plan220, plan221, plan222, plan223, plan224, plan225, plan226, plan227, plan228, plan229, plan230, plan231, plan232, plan233, plan234, plan235, "
[5] " plan236, plan237, plan238, plan239, plan240, plan241, plan242, plan243, plan244, plan245, plan246, plan247, plan248, plan249, plan250, plan251, plan252, plan253, plan254, plan255, plan256, plan257, plan258, plan259, plan260, plan261, plan262, plan263, plan264, plan265, plan266, plan267, plan268, plan269, plan270, plan271, plan272, plan273, plan274, plan275, plan276, plan277, plan278, plan279, plan280, plan281, plan282, plan283, plan284, plan285, plan286, plan287, plan288, plan289, plan290, plan291, "
[6] " plan292, plan293, plan294, plan295, plan296, plan297, plan298, plan299, plan300, plan301, plan302, plan303, plan304, plan305, plan306, plan307, plan308, plan309, plan310, plan311, plan312, plan313)"
When model.matrix.default tests this against the variables in the data.frame, it returns an error.
The problem
To get around this, I've written a new deparse function:
deparse <- function (expr, width.cutoff = 60L, backtick = mode(expr) %in%
c("call", "expression", "(", "function"), control = c("keepInteger",
"showAttributes", "keepNA"), nlines = -1L) {
ret <- .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), nlines))
paste0(ret,collapse="")
}
However, when I run mnp again and step through, it returns the same error for the same reason (base::deparse is being run, not my deparse).
This is somewhat surprising to me, as what I expect is more typified by this example, where the user-defined function temporarily over-writes the base function:
> print <- function() {
+ cat("user-defined print ran\n")
+ }
> print()
user-defined print ran
I realize the right way to solve this problem is to rewrite model.matrix.default, but as a tool for debugging I'm curious how to force it to use my deparse and why the anticipated (by me) behavior is not happening here.
The functions fixInNamespace and assignInNamespace are provided to allow editing of existing functions. You could try ... but I will not since mucking with deparse looks too dangerous:
assignInNamespace("deparse",
function (expr, width.cutoff = 60L, backtick = mode(expr) %in%
c("call", "expression", "(", "function"), control = c("keepInteger",
"showAttributes", "keepNA"), nlines = -1L) {
ret <- .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), nlines))
paste0(ret,collapse="")
} , "base")
There is an indication on the help page that the use of such functions has restrictions and I would not be surprised that such core function might have additional layers of protection. Since it works via side-effect, you should not need to assign the result.
This is how packages with namespaces search for functions, as described in Section 1.6, Package Namespaces of Writing R Extensions
Namespaces are sealed once they are loaded. Sealing means that imports
and exports cannot be changed and that internal variable bindings
cannot be changed. Sealing allows a simpler implementation strategy
for the namespace mechanism. Sealing also allows code analysis and
compilation tools to accurately identify the definition corresponding
to a global variable reference in a function body.
The namespace controls the search strategy for variables used by
functions in the package. If not found locally, R searches the package
namespace first, then the imports, then the base namespace and then
the normal search path.

TokyoCabinet's Ruby C interface can't bzip

I'm using the Ruby official Ruby C interface and am not able to bzip working. It did build with bzip support, ./configure said:
checking bzlib.h usability... yes
checking bzlib.h presence... yes
checking for bzlib.h... yes
So I wrote this example program that just writes an entry to two files, one supposedly bzip'd and one not. Neither is compressed; aside from the simple file size test at the end I can edit the with_bzip.tcb
file and see the raw string text there.
require 'tokyocabinet'
include TokyoCabinet
def write filename, options
File.unlink filename if File.exists? filename
bdb = BDB::new
bdb.tune(0, 0, 0, -1 -1, options) or raise "Couldn't tune"
bdb.open(filename, BDB::OWRITER | BDB::OCREAT | BDB::OLCKNB) or raise "Couldn't open"
bdb["test"] = "This string should be compressed and not appear raw.\n" * 10000
bdb.close
end
write 'without_bzip.tcb', 0
write 'with_bzip.tcb', BDB::TBZIP
puts "Not actually compressed" unless File.size('with_bzip.tcb') < File.size('without_bzip.tcb')
What makes it worse is that if I try a preview release of Oklahoma Mixer (example following - though I don't have the reputation to add the new tag), it compresses fine. When I tucked some debugging into its try() call, it seems to be making the same call to tune(0, 0, 0, -1, -1, 4). I'm pretty completely stumped - can anyone tell me what my code above is doing wrong?
require 'oklahoma_mixer'
OklahomaMixer.open("minimal_om.tcb", :opts => 'lb') do |db|
db["test"] = "This string should be compressed and not appear raw.\n" * 10000
end
It is an evil, subtle bug. I left out a comma in the tune() call and wrote -1 -1 instead of -1, -1. All the arguments are optional, so it was quietly not bzipping. Argh.

CUDAPP 1.1 cudppSort configuration error (Invalid configuration argument)

I am trying to call cudppSort to sort a set of keys/values. I'm using the following code to set up the sort algorithm:
CUDPPConfiguration config;
config.op = CUDPP_ADD;
config.datatype = CUDPP_UINT;
config.algorithm = CUDPP_SORT_RADIX;
config.options = CUDPP_OPTION_KEY_VALUE_PAIRS | CUDPP_OPTION_FORWARD | CUDPP_OPTION_EXCLUSIVE;
CUDPPHandle planHandle;
CUDPPResult result = cudppPlan(&planHandle, config, number_points, 1, 0);
if (CUDPP_SUCCESS != result) {
printf("ERROR creating CUDPPPlan\n");
exit(-1);
}
The program exits, however on the line:
CUDPPResult result = cudppPlan(&planHandle, config, number_points, 1, 0);
and prints to stdout:
Cuda error: allocScanStorage in file 'c:/the/path/to/release1.1/cudpp/src/app/scan_app.cu' in line 279 : invalid configuration argument.
I looked at the line in scan_app.cu. It is,
CUT_CHECK_ERROR("allocScanStorage");
So apparently my configuration has an error that is causing the allocScanStorage to bomb out. There are only two calls to CUDA_SAFE_CALL in the function and I don't see a reason why either has anything to do with the configuration.
What is wrong with my configuration?
So that this doesn't sit around as an unanswered question (I'm not sure if this is the right SO etiquette but it seems like an answered question shouldn't sit around unanswered...), I'm copying the comment I made above here as an answer since it was the solution:
I figured this out (I'm still learning CUDA at the moment.) Because the error checking is asynchronous errors can show up in strange places if you don't check for them from time to time. My code had caused an error before I called cudppPlan but because I didn't check for errors the cudppPlan reported the error as if it was in cudppPlan.

Resources