Skip to content
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

ToDo list #472

Closed
15 of 20 tasks
jarun opened this issue Feb 12, 2020 · 51 comments
Closed
15 of 20 tasks

ToDo list #472

jarun opened this issue Feb 12, 2020 · 51 comments

Comments

@jarun
Copy link
Owner

jarun commented Feb 12, 2020

Rolled from #448.

For next release

  • unlimited bookmarks and plugin keys
  • env var NNN_OPTS to specify binary options to nnn
  • ignore hard links when calculating disk usage
  • dim link names
  • add entry to selection on right click
  • more special keys at empty filter prompt in nav-as-you-type mode
  • move to next entry on current file delete
  • use s in status bar to indicate selection in progress
  • make variable O_NOMOUSE to disable mouse support
  • honor NNN_TRASH and -Q always, do not store in config/session
  • nuke - open log files in vi
  • fix PCRE case-insensitive regex search
  • fix static package generation
  • fix broken abort message when started in du-mode
  • fix filter lost on context switch in non nav-as-you-type mode

Proposed features and tasks (up for grabs)

  • support long press to open files (@0xACE)
  • a POSIX-compliant sh plugin with vidir-like functionality (@KlzXS)
  • support pre-defined filters like bookmarks
  • update the nnn.vim plugin to show a persistent bar (Support vim popup mcchrish/nnn.vim#46)
  • a video exploring nnn plugins

Anything else which would add value (please discuss in this thread).

@alosich
Copy link

alosich commented Feb 12, 2020

Filtering is case insensitive for english names, but case sensitive for russian.

└> ls
test  Test  тест  Тест

"te" selects both "Test" and "test", while "те" selects only "тест" missing "Тест".

It's expected to be case insensitive not depending on language.

Tested on latest master.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

By default, we do use setlocale() and REG_ICASE (or PCRE_CASELESS).

I think the issue may be with UTF8. As per the following man page: http://man7.org/linux/man-pages/man3/pcreposix.3.html REG_UTF8 is not POSIX. Can you try the PCRE version with the following patch:

diff --git a/src/nnn.c b/src/nnn.c
index a31b30e..571530e 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -2059,7 +2059,7 @@ static char xchartohex(char c)
 static char * (*fnstrstr)(const char *haystack, const char *needle) = &strcasestr;
 #ifdef PCRE
 static const unsigned char *tables;
-static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS;
+static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS | PCRE_UTF8;
 #else
 static int regflags = REG_NOSUB | REG_EXTENDED | REG_ICASE;
 #endif

To compile with PCRE, run:

sudo make O_PCRE=1 strip install

@alosich
Copy link

alosich commented Feb 12, 2020

└> git diff
diff --git a/src/nnn.c b/src/nnn.c
index a31b30e..571530e 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -2059,7 +2059,7 @@ static char xchartohex(char c)
 static char * (*fnstrstr)(const char *haystack, const char *needle) = &strcasestr;
 #ifdef PCRE
 static const unsigned char *tables;
-static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS;
+static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS | PCRE_UTF8;
 #else
 static int regflags = REG_NOSUB | REG_EXTENDED | REG_ICASE;
 #endif
└> make O_PCRE=1 strip
cc -DPCRE -Wall -Wextra -O3 -D_GNU_SOURCE -D_DEFAULT_SOURCE   -o nnn src/nnn.c -lreadline -lpcre -lncursesw 
strip nnn
└> ./nnn

same behavior.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

I think either the library is not working correctly OR we need to do something extra that I am not aware of. I don't know Russian. Please raise a defect on libpcre and see what they have to say.

@alosich
Copy link

alosich commented Feb 12, 2020

Hm, I just retested, and if I filter by using regex (by doing // - the \ in prompt) it filters correctly, while when doing string filtering (when / in prompt) the problem shows.

So, when doing the regex filtering (\ in prompt) the patch helps (I checked without it to confirm).

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

At the filter prompt:

  • press / to toggle string and regex
  • press : to toggle case-sensitivity

When the prompt shows /, it's string. When it shows \, it's regex.

Try this without the patch:

Start in string filter mode (default), press : and see if case-insensitive search works.

@alosich
Copy link

alosich commented Feb 12, 2020

Testing without patch: in string search mode (/ in prompt):

started:

[1 2 3 4] /test

 test
 Test
 тест
 Тест






                                     str [/], ic [:]
/

search for "te" with default mode, shows both "test" and "Test" as expected:

[1 2 3 4] /test

 test
 Test








                                     str [/], ic [:]
/te

searching for "te" in case sensitive mode ("noic") shows only "test" as expected:

[1 2 3 4] /test

 test









                                   str [/], noic [:]
/te

searching for "те" in default mode shows only "тест", and not shows "Тест":

[1 2 3 4] /test

 тест









                                     str [/], ic [:]
/те

searching for "те" in case insensitive mode ("noic") shows only "тест" as expected:

[1 2 3 4] /test

 тест









                                   str [/], noic [:]
/те

searching for regex "te":

[1 2 3 4] /test

 test
 Test








                                   regex [/], ic [:]
\te

searching for regex "те" (without patch):

[1 2 3 4] /test

 тест










                            regex [/], ic [:]
\те

note, that is tested on latest master. I have 2.9 version installed in system, and surprisingly, regex searching in it works correct:

[1 2 3 4] /test

 тест
 Тест









                            regex [/], ic [:]
\те

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

Did you build master with PCRE or without PCRE?

@alosich
Copy link

alosich commented Feb 12, 2020

make O_PCRE=1 clean strip

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

OK. I compiled master without PCRE (and without patch):

sudo make strip install

And here's what I see:

[1 2 3 4] /home/vaio/GitHub/nnn/test

 тест
 Тест











                                                                regex [/], ic [:]
\те

Which I think is expected.

My locale output:

$ locale        
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=en_IN.UTF-8
LC_TIME=en_IN.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=en_IN.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=en_IN.UTF-8
LC_NAME=en_IN.UTF-8
LC_ADDRESS=en_IN.UTF-8
LC_TELEPHONE=en_IN.UTF-8
LC_MEASUREMENT=en_IN.UTF-8
LC_IDENTIFICATION=en_IN.UTF-8
LC_ALL=

@alosich
Copy link

alosich commented Feb 12, 2020

For regex that's expected, yes. But string search gives different result.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

And yes, when I compile with PCRE (without the pacth), I do see the issue in regex. I think we need the patch for regex.

I can repro the issue with string search with the above examples. In this case regex does not take effect as well.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

Also, with string search the issue exists in v2.9 as well.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

I think the problem is with using strcasestr. noic (strstr() works fine).

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

If I see the man page of strstr or strcasestr:

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌─────────────┬───────────────┬────────────────┐
       │Interface    │ Attribute     │ Value          │
       ├─────────────┼───────────────┼────────────────┤
       │strstr()     │ Thread safety │ MT-Safe        │
       ├─────────────┼───────────────┼────────────────┤
       │strcasestr() │ Thread safety │ MT-Safe locale │
       └─────────────┴───────────────┴────────────────┘

which essentially tells me strcasestr depends on the locale. @KlzXS @annagrram are you aware of any locale independent api that can do this? Otherwise I think we will have to convert both the strings to lowercase and do the comparison.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

converting to lowercase is also locale dependent, so it will not help.

@0xACE
Copy link
Collaborator

0xACE commented Feb 12, 2020

Iirc, normalizing UTF-8 strings is going to require a huge external library to help with normalizing it, and afaik it's not 100% foolproof.

Btw, I would propose that regex keeps the / symbol, and another symbol is found for regular text search. The reason I propose this is because then at least you can copy paste the line and not have to worry that \ will escape something if you paste it into grep or other utilities.

I'm not in sync with master since december since there were some changes that are huge merge conflict for me, so I'm way behind atm, until I can find the time to correct the merge conflicts.

@jarun
Copy link
Owner Author

jarun commented Feb 12, 2020

Iirc, normalizing UTF-8 strings is going to require a huge external library to help with normalizing it, and afaik it's not 100% foolproof.

Yes, I think it's not simple to achieve this.

@alosich with the PCRE fix in, I would suggest you use regex (POSIX or PCRE) for this use case. We can document this limitation.

The reason I propose this is because then at least you can copy paste the line and not have to worry that \ will escape something if you paste it into grep or other utilities.

Hey, it looks cool and is easy to figure. Copy/paste carefully all the time. ;)

@alosich
Copy link

alosich commented Feb 13, 2020

I would suggest you use regex (POSIX or PCRE) for this use case. We can document this limitation.

works for me.

@jarun
Copy link
Owner Author

jarun commented Feb 13, 2020

I have updated the documentation here: https://github.com/jarun/nnn/wiki#limitation

@jarun
Copy link
Owner Author

jarun commented Feb 21, 2020

@KlzXS @0xACE @maximbaz

I have a question on the cfg.trash variable. As it is in the cfg it's saved in sessions. Say at some point the user didn't have NNN_TRASH set and he saved a session. Later he wanted to trash and set NNN_TRASH. However, when he loads the session, cfg.trash would be lost and when he deletes a file it would be unrecoverable.

I think when we say, NNN_TRASH determines the behaviour we should honor the runtime env var instead of the config retrieved from the stored session. So I think we should not save it in the config. What do you guys think?

@jarun
Copy link
Owner Author

jarun commented Feb 21, 2020

Implemented at commit ca257e6 as I had some time. But this is still open for discussion,

@maximbaz
Copy link
Contributor

I agree with what you did 👍

@jarun
Copy link
Owner Author

jarun commented Feb 21, 2020

BTW, I am enjoying v3.0 (+ O_NOMOUSE) thoroughly. 3.0 feels like an achievement.

@maximbaz
Copy link
Contributor

Me too!

+ O_NOMOUSE

Huh, I didn't realize until now that mouse is supported, I never even thought to try to use mouse in nnn before 😄

@jarun
Copy link
Owner Author

jarun commented Feb 21, 2020

I used to realize it now and then when clicking to bring the terminal above other windows.

It reduces memory usage and binary size. On my system I have O_NORL + O_NOMOUSE and the size is 70.1KiB.

@JustAPerson
Copy link

If you filter in a context, the filter will be gone when you return to that context after switching away. This was pretty annoying for some work I was doing.

I tried to fix this but ran into a deadlock. It shows the correct results on the screen but stops responding to input :(

diff --git a/src/nnn.c b/src/nnn.c
index 3e161db..9c6a3ba 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -4966,6 +4966,7 @@ begin:
 		blk_shift = BLK_SHIFT_512;
 		presel = CONTROL('L');
 	}
+	matches(g_ctx[cfg.curctx].c_fltr + 1);
 
 #ifdef LINUX_INOTIFY
 	if (presel != FILTER && inotify_wd == -1)

From what I read, when you change contexts, there's a switch-statement in browse() that has a case for SEL_CTX* and then it jumps to the begin: label and repopulates the directory entry array. I tried adding a call to matches() after this point, but it causes a deadlock whenever you return to a context that was filtered.

Also I now realize that the UI could use work. It's not obvious when you return to a filtered context that you are seeing a subset of directory entries. You can press ^L to remove the filter, but maybe there should be something obvious to warn the user that a filter is in place.

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

In which version are you? These are all fixed. In v3.0 the filter is retained and applied when you return to a context. And obviously the filter is shown in the filter prompt.

@JustAPerson
Copy link

JustAPerson commented Feb 26, 2020

In which version are you?

git master

These are all fixed. In v3.0 the filter is retained and applied when you return to a context. And obviously the filter is shown in the filter prompt.

No it is not.

  • Open two contexts (in different directories)
  • press / and type a filter query
  • press ESC to finalize the filter so you can actually navigate in the context and do things with the files
  • press 2 to go second context and then press 1 return to first one
  • now the directory filter has disappeared and the entire directory's contets are visible.

This is what I mean
asciicast
https://asciinema.org/a/ot4QfHGAl4t9lHPYlUduYkzov

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

OK. I got the difference between your your use case and mine. I am in nav-as-you-type mode, you are not.

Commit 3d5391c should fix this.

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

@JustAPerson please test with commit f0f8008. The previous one was not to my liking.

@lawnowner
Copy link
Contributor

When the below directory in an ext4 partition is entered and the du is toggled
with td, nnn exits with segmentation fault:

File: /home/lo/Desktop/Apollo - loc analysis
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 821h/2081d Inode: 21634578 Links: 3

However, when the same directory is copied to another ext4 partition with both
less capacity and less disk usage, the du toggle works fine:

File: /home/Apollo - loc analysis
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 803h/2051d Inode: 1845697 Links: 3

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

@lawnowner I think it's obvious I can't repro it on my system. Please enable debug logs and get your hands dirty.

Also,

  • in which version are you? does this appear on master?
  • do you see the issue in v2.8 and v2.9? This will help us determine if this is a regression.

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

@lawnowner another option would be to compile in debug mode and run in gdb. When you get the segfault run bt full to get the line number in which the crash occurred.

@lawnowner
Copy link
Contributor

Segv happens at the line 710 of nnn.c: *m |= 1 << (nr & 63); . Apparently the issue is introduced with the commint 4a91df9, where the 24-bit hash bitmap that is defined for in-memory hard link detection may not be enough for larger inode numbers: #define HASH_BITS (0xFFFFFF). Using a 32-bit constant prevents the segmentations fault, while also accounting for the maximum number inodes in ext4.

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

Got it! A 32-bit HASH_BITS will increase the virtual memory usage drastically. So we need to figure a more efficient algo.

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

@lawnowner can you please confirm if the following patch works:

diff --git a/src/nnn.c b/src/nnn.c
index ea37f2b..3dcf76b 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -702,6 +702,7 @@ static char *xitoa(uint val)
  */
 static bool test_set_bit(ull nr)
 {
+       nr = nr & HASH_BITS;
        ull *m = ((ull *)ihashbmp) + (nr >> 6);
 
        if (*m & (1 << (nr & 63)))
@@ -4179,7 +4180,7 @@ static void launch_app(const char *path, char *newpath)
 static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
 {
        if (sb->st_blocks && (typeflag == FTW_F || typeflag == FTW_D)
-           && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+           && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
                ent_blocks += sb->st_blocks;
 
        ++num_files;
@@ -4189,7 +4190,7 @@ static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typef
 static int sum_asize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
 {
        if (sb->st_size && (typeflag == FTW_F || typeflag == FTW_D)
-           && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+           && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
                ent_blocks += sb->st_size;
 
        ++num_files;
@@ -4309,7 +4310,8 @@ static int dentfill(char *path, struct entry **dents)
                                }
                        } else {
                                /* Do not recount hard links */
-                               if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+                               if (sb.st_nlink <= 1
+                                   || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
                                        dir_blocks += (cfg.apparentsz ? sb.st_size : sb.st_blocks);
                                ++num_files;
                        }
@@ -4406,7 +4408,8 @@ static int dentfill(char *path, struct entry **dents)
                        } else {
                                dentp->blocks = (cfg.apparentsz ? sb.st_size : sb.st_blocks);
                                /* Do not recount hard links */
-                               if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+                               if (sb.st_nlink <= 1
+                                   || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
                                        dir_blocks += dentp->blocks;
                                ++num_files;
                        }

@jarun
Copy link
Owner Author

jarun commented Feb 26, 2020

@lawnowner ignore the previous patch. Try the following (I have reduced the hash bits further):

diff --git a/src/nnn.c b/src/nnn.c
index ea37f2b..24fe374 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -165,7 +165,7 @@
 #define BLK_SHIFT_512 9
 
 /* Detect hardlinks in du */
-#define HASH_BITS (0xFFFFFF)
+#define HASH_BITS (0xFFFF)
 #define HASH_OCTETS (HASH_BITS >> 6) /* 2^6 = 64 */
 
 /* Program return codes */
@@ -702,6 +702,7 @@ static char *xitoa(uint val)
  */
 static bool test_set_bit(ull nr)
 {
+	nr = nr & HASH_BITS;
 	ull *m = ((ull *)ihashbmp) + (nr >> 6);
 
 	if (*m & (1 << (nr & 63)))
@@ -4179,7 +4180,7 @@ static void launch_app(const char *path, char *newpath)
 static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
 {
 	if (sb->st_blocks && (typeflag == FTW_F || typeflag == FTW_D)
-	    && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+	    && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
 		ent_blocks += sb->st_blocks;
 
 	++num_files;
@@ -4189,7 +4190,7 @@ static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typef
 static int sum_asize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
 {
 	if (sb->st_size && (typeflag == FTW_F || typeflag == FTW_D)
-	    && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+	    && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
 		ent_blocks += sb->st_size;
 
 	++num_files;
@@ -4309,7 +4310,8 @@ static int dentfill(char *path, struct entry **dents)
 				}
 			} else {
 				/* Do not recount hard links */
-				if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+				if (sb.st_nlink <= 1
+				    || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
 					dir_blocks += (cfg.apparentsz ? sb.st_size : sb.st_blocks);
 				++num_files;
 			}
@@ -4406,7 +4408,8 @@ static int dentfill(char *path, struct entry **dents)
 			} else {
 				dentp->blocks = (cfg.apparentsz ? sb.st_size : sb.st_blocks);
 				/* Do not recount hard links */
-				if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+				if (sb.st_nlink <= 1
+				    || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
 					dir_blocks += dentp->blocks;
 				++num_files;
 			}

@lawnowner
Copy link
Contributor

The segmentation fault returns after decreasing the variable width from ull to ulong at the commit c6cc8a5.

You can reproduce the issue with test_set_bit() by setting the nr value in gdb regardless of whether your file system naturally produces it or not, but now the segv occurs even in the system directories (e.g. /usr) when the du toggle is switched.

@jarun
Copy link
Owner Author

jarun commented Feb 27, 2020

Yes, I have to reduce the width as well. I had to leave after the change. I'll fix it and update you to confirm.

@jarun
Copy link
Owner Author

jarun commented Feb 27, 2020

@lawnowner please confirm with commit 9535668. I think it's fixed now.

@maximbaz
Copy link
Contributor

@jarun I noticed that if you remove a file in nnn with x, the selection goes to the previous file (line above) and not to the next file (line below). This is inconsistent with how text editors like vim work (when you dd a line, your cursor will go the next line), and also this makes it a bit more annoying when you want to delete 3 files, you must click xjxjx or <space><space><space>xs instead of simply xxx.

Do you know if this is something that can be easily done? I tried to look into the code but it's not immediately obvious to me where this selection happens after you delete a file.

@jarun
Copy link
Owner Author

jarun commented Feb 28, 2020

@maximbaz I think it can be done easily. I'll make the change.

@jarun
Copy link
Owner Author

jarun commented Feb 28, 2020

@maximbaz this should be fixed at commit 76cf0c6. Please confirm.

@JustAPerson
Copy link

JustAPerson commented Feb 28, 2020

@JustAPerson please test with commit f0f8008. The previous one was not to my liking.

This works somewhat.
When you return to a context, now the filter is active (and you can edit the filter), but I see two problems.

  • The filter is currently editable, which means you have to press ESC to do things with the files in the context again. To have left this context in the first place, we already hit ESC once before we could hit 2 to go to a new context (otherwise the 2 would've become part of the filter). On one hand, this informs the user that there is an active filter but on the other, it's kind of annoying. I'm not sure this is a good UX. I don't think we should leave it like this.
  • Once the filter is editable after returning a context, pressing RET causes a bug where nnn enters a weird state. It seems to ignore lots of keypresses randomly.

Valgrind says this is because of uninitalized memory (these line numbers are f0f8008):

==16737== Memcheck, a memory error detector
==16737== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16737== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16737== Command: ./nnn
==16737== 
==16737== Conditional jump or move depends on uninitialised value(s)
==16737==    at 0x566DE77: __wcsnlen_avx2 (strlen-avx2.S:261)
==16737==    by 0x559BEC1: wcsrtombs (wcsrtombs.c:104)
==16737==    by 0x5521B20: wcstombs (wcstombs.c:34)
==16737==    by 0x110375: filterentries (nnn.c:2541)
==16737==    by 0x1186F7: browse (nnn.c:5415)
==16737==    by 0x11CAEF: main (nnn.c:6808)

I first noticed this bug on f0f8008 but it occurs on the commit before and also master.

I can find even more undefined behavior on master (these line numbers are from 76cf0c6):

==17387== Conditional jump or move depends on uninitialised value(s)
==17387==    at 0x5505458: internal_utf8_loop (loop.c:298)
==17387==    by 0x5505458: __gconv_transform_internal_utf8 (skeleton.c:609)
==17387==    by 0x559BEF4: wcsrtombs (wcsrtombs.c:110)
==17387==    by 0x5521B20: wcstombs (wcstombs.c:34)
==17387==    by 0x110368: filterentries (nnn.c:2563)
==17387==    by 0x1187DE: browse (nnn.c:5454)
==17387==    by 0x11CBF1: main (nnn.c:6851)
==17387== 
==17387== Conditional jump or move depends on uninitialised value(s)
==17387==    at 0x566DE77: __wcsnlen_avx2 (strlen-avx2.S:261)
==17387==    by 0x559BEC1: wcsrtombs (wcsrtombs.c:104)
==17387==    by 0x5521B20: wcstombs (wcstombs.c:34)
==17387==    by 0x1100A9: filterentries (nnn.c:2470)
==17387==    by 0x1187DE: browse (nnn.c:5454)
==17387==    by 0x11CBF1: main (nnn.c:6851)
==17387== Use of uninitialised value of size 8
==17387==    at 0x560E6AE: __lll_lock_wait_private (lowlevellock.S:96)
==17387==    by 0x55DF6F6: regexec@@GLIBC_2.3.4 (regexec.c:215)
==17387==    by 0x10F375: visible_re (nnn.c:2143)
==17387==    by 0x10FD0D: fill (nnn.c:2383)
==17387==    by 0x10FDC7: matches (nnn.c:2416)
==17387==    by 0x110374: filterentries (nnn.c:2570)
==17387==    by 0x1187DE: browse (nnn.c:5454)
==17387==    by 0x11CBF1: main (nnn.c:6851)
==17387== 
==17387== Syscall param futex(futex) contains uninitialised byte(s)
==17387==    at 0x560E6AC: __lll_lock_wait_private (lowlevellock.S:95)
==17387==    by 0x55DF6F6: regexec@@GLIBC_2.3.4 (regexec.c:215)
==17387==    by 0x10F375: visible_re (nnn.c:2143)
==17387==    by 0x10FD0D: fill (nnn.c:2383)
==17387==    by 0x10FDC7: matches (nnn.c:2416)
==17387==    by 0x110374: filterentries (nnn.c:2570)
==17387==    by 0x1187DE: browse (nnn.c:5454)
==17387==    by 0x11CBF1: main (nnn.c:6851)

I also found a segfault at one point doing some random stuff but that one is harder to replicated.

@maximbaz
Copy link
Contributor

@maximbaz this should be fixed at commit 76cf0c6. Please confirm.

Confirmed, thanks a lot! 👍

@jarun
Copy link
Owner Author

jarun commented Feb 28, 2020

@JustAPerson

this informs the user that there is an active filter

That's the intention. With different filters applied and 4 contexts open, this is indeed helpful. What problem are you facing? Despite the filter showing there, up, down, enter. control keypresses work seamlessly. You do not need to clear the filter with Esc beforehand.

Once the filter is editable after returning a context, pressing RET causes a bug where nnn enters a weird state. It seems to ignore lots of keypresses randomly.

I can't reproduce this! More detailed steps please. Are you restoring from a session? When you press RET are you hovering on a dir or a file? For me if it's a file, the file is opened, if it's a dir, it's entered.

@jarun
Copy link
Owner Author

jarun commented Feb 28, 2020

I can repro it now.

@jarun
Copy link
Owner Author

jarun commented Mar 1, 2020

@JustAPerson in filterentries() can you uncomment the following 2 lines:

                //DPRINTF_D(*ch);
                //DPRINTF_S(keyname(*ch));

and see what keypress you get when you press Enter? For me it's '\r` (and ^M).

@JustAPerson
Copy link

On 76cf0c6

ln 2453: *ch=13
ln 2454: keyname(*ch)=^M

*ch=13 is carriage return \r.

I definitely think you should pursue fixing any undefined behavior in nnn, which it seems like there might be a fair bit of. Try exploring -fsanitize.

I will not be responding to this issue further.

@jarun
Copy link
Owner Author

jarun commented Mar 2, 2020

@JustAPerson nnn uses a shortcut to remember the last filter in-place in ln. The NULL terminator is also stored in-place however the start of the filter is hidden away. I am not sure your tool sees through that. That's the reason I wanted to concentrate on the issue you see. Anyway, I'm sure someone else will see it and report if you don't have the time.

@jarun jarun mentioned this issue Mar 2, 2020
35 tasks
@jarun jarun closed this as completed Mar 2, 2020
Repository owner locked as resolved and limited conversation to collaborators Mar 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants